题解:P13447 [GCJ 2009 #3] Interesting Ranges
思路
首先考虑前缀和,设
显然求出
差分为
若第
设
考虑如何规避最后一位是
- 若
x 位数大于等于2 ,设x 除去最后一位的数y ,发现我们可以统计y 后跟上一个0\sim 9 中偶数的答案,这样就不会出现最后一位是9 的情况。然后发现每个y 对应的回文数个数为偶数,所以对于其他的y ,仍然只需要记录最后一位是偶数的情况; - 否则,这个回文数不会超过
100 ,直接暴力枚举即可。
发现我们现在记录的个数相当于
若
此时考虑计算
对于位数等于
- 若最长公共前缀长度小于
\lfloor\frac{len-1}2\rfloor ,最后一定剩下一位可以随便填,那么最后一位就可以取到0\sim 9 的任意一个偶数。对答案的贡献计算方式和f 类似; - 否则,最多剩下一位,暴力枚举计算贡献即可。
记得对于
时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6+5,mod = 1e9+7,inv2 = (mod+1)>>1;
int pw[N],f[N],sum[N];
inline int get(int x){x = (x+mod)%mod;return x*(x-1)%mod*inv2%mod;}
inline int get(string &s)
{
int res = 0;
for(int i = 0;i<s.size();i++) (res+=pw[s.size()-i-1]*(s[i]-'0'))%=mod;
return res;
}
string s,t;
inline int work()
{
if(s.size()&&s[0]<'0') return 0;
if(s.size()==0) return 0;
if(s.size()==1) return sum[s[0]-'0'];
if(s.size()==2)
{
int now = (s[0]-'0')*10+s[1]-'0';
return sum[now];
}
int n = s.size();
int res = 0;
for(int i = 0;i<n;i++) (res+=f[i])%=mod;
bool fl = 1;
int w = pw[n/2];
if(n%2==0) (w+=pw[n/2-1])%=mod;
for(int i = 0;i<(n-1)/2;i++)
{
int x = pw[(n-2*(i+1)-1)/2];
(res+=x*w%mod*5*(s[i]-'0'-(i==0)))%=mod;
}
t.resize(n);
for(int i = 0;i<10;i+=2)
{
for(int j = 0;j<(n-1)/2;j++)
t[j] = t[n-j-1] = s[j];
t[(n-1)/2] = i+'0';
if(n%2==0) t[n/2] = i+'0';
bool fl1 = (t<=s);
t[(n-1)/2]++;
if(n%2==0) t[n/2]++;
bool fl2 = (t<=s);
if(fl2)
{
(res+=w)%=mod;
}
else if(fl1)
{
t[(n-1)/2]--;
if(n%2==0) t[n/2]--;
(res+=get(s)-get(t)+1+mod)%=mod;
}
else break;
}
return res;
}
inline void solve()
{
cin>>s;
s[s.size()-1]-=2;
int p = s.size()-1;
while(p>0&&s[p]<'0')
{
s[p]+=10;
s[p-1]--;
}
if(s[0]=='0') s.erase(s.begin());
int ans = mod-work(),len = mod-get(s);
cin>>s;
(ans+=work())%=mod;
(len+=get(s))%=mod;
cout<<(get(ans)+get(len-ans))%mod<<'\n';
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
pw[0] = 1;
for(int i = 1;i<N;i++) pw[i] = pw[i-1]*10%mod;
int now = 0;
for(int i = 1;i<100;i++)
{
if(i<10||i%11==0) now^=1;
sum[i] = sum[i-1]+now;
}
f[1] = sum[9];
f[2] = sum[99]-sum[9];
for(int i = 3;i<N;i++)
{
int cnt = (pw[(i-1)/2]-pw[(i-1)/2-1]+mod)%mod,w = pw[i/2];
if(i%2==0) (w+=pw[i/2-1])%=mod;
f[i] = cnt*w%mod*5%mod;
}
int T;cin>>T;
for(int _ = 1;_<=T;_++)
{
cout<<"Case #"<<_<<": ";
solve();
}
return 0;
}