题意:只有满足“存在长度至少为2的回文子串”的数是萌的——也就是说,101是萌的,因为101本身就是一个回文数;110是萌的,因为包含回文子串11;但是102不是萌的,1201也不是萌的.求([l,r])所有整数中有多少个萌数.由于答案可能很大,所以只需要输出答案对(1e9+7)的余数.记(n)为(r)在十进制下的位数,(n<=1000,l<r.)
分析:考虑求出([l,r])内有多少个数不是萌数,它们一定满足第(i)位不等于第(i-1)位且第(i)位不等于第(i-2)位.(因为对于一个回文串(a),它在中心对称的地方一定满足(a[i]=a[i-1])或者(a[i]=a[i-2]))
因为数字特别大,我们以字符串的形式读入,然后一边取模一边变成(l,r),设([l,r])内有(ans)个数不是萌数,则最终的答案就是(r-l+1-ans.)
然后我们还是先求出([1,r])内不是萌数的个数(ans2),再求([1,l])内不是萌数的个数(ans1),然后我们判断一下(l)是不是萌数,若(l)不是萌数则(--ans1),则([l,r])内不是萌数的个数为(ans2-ans1)个.(这样搞就可以不用判断(l)是否为(0)了).
一碰到字符串,就必定要注意数组下标等细节问题了.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
const int mod=1e9+7;
string s1,s2;
int n,m,a[1005],b[1005];
ll l,r,dp[1005][10][10];
inline ll dfs(int tot,int pos,int pre2,int pre1,int lead,int limit){
if(pos>tot)return 1;//找到了一个不是萌数的数
if(pre2!=-1&&pre1!=-1)//防止数组下标越界
if(dp[pos][pre1][pre2]!=-1&&!lead&&!limit)return dp[pos][pre1][pre2];
ll cnt=0;int res=limit?a[tot+1-pos]:9;
for(int i=0;i<=res;++i){
if((i==pre1)||(i==pre2))continue;
if((!i)&&lead)cnt=(cnt+dfs(tot,pos+1,-1,-1,1,limit&&(i==res)))%mod;
else if(i&&lead)cnt=(cnt+dfs(tot,pos+1,-1,i,0,limit&&(i==res)))%mod;
else cnt=(cnt+dfs(tot,pos+1,pre1,i,0,limit&&(i==res)))%mod;
}
if(pre2!=-1&&pre1!=-1&&!lead&&!limit)dp[pos][pre1][pre2]=cnt;//防止数组下标越界
return cnt;
}
inline ll solve(){
for(int i=0;i<n;++i)a[i+1]=s1[n-1-i]-'0';//把下标挪到1-n来
memset(dp,-1,sizeof(dp));ll ans1=dfs(n,1,-1,-1,1,1);
for(int i=0;i<m;++i)a[i+1]=s2[m-1-i]-'0';
memset(dp,-1,sizeof(dp));ll ans2=dfs(m,1,-1,-1,1,1);
for(int i=0;i<n;++i)a[i+1]=s1[n-1-i]-'0';
--ans1;//先假设l不是萌数
for(int i=2;i<=n;i++)
if(a[i]==a[i-1]||(a[i]==a[i-2]&&(i-2>=1))){
ans1++;//如果l是萌数,再加回来
break;
}
return ans2-ans1;
}
int main(){
cin>>s1>>s2;n=s1.size();m=s2.size();
for(int i=0;i<n;++i)l=(1ll*l*10+s1[i]-'0')%mod;
for(int i=0;i<m;++i)r=(1ll*r*10+s2[i]-'0')%mod;
printf("%lld
",((r-l+1-solve())%mod+mod)%mod);
return 0;
}