Description
Victor 是一名热爱数字的同学。他最近在思考这样一个问题:
一个字符串是回文的当且仅当它倒过来还和原来相同。那么如果一个数的数串没有一个长度超过1 的子串是回文串的话,它就是palindrome-free 的。例如:16276 是palindrome-free的,而17276 不是,因为它包含了回文串727。
Victor 想知道在a 到b 的区间内,有多少个数是palindrome-free 的。
Input
从文件numbers.in 中读入数据。
包括两个数字a,b。
Output
输出到文件numbers.out 中。
输出包含一个整数:区间a,…,b 中palindrome-free 的数的总个数(包括a,b)。
Sample Input
输入1:
123 321
输入2:
123456789 987654321
Sample Output
输出1:
153
输出2:
167386971
Data Constraint
对于16% 的数据,b - a <= 200。
对于24% 的数据,b - a <= 10^5。
对于32% 的数据,b - a <= 10^6。
对于100% 的数据,0 <= a <= b <= 10^18
想法:
数论,ans=ans(b)-ans(a-1);
如果一个数是palindrome-free的,则必有s[i]==s[i+1]||s[i]==s[i+2]
32%
如何求ans(x)?
设f[i][j][k][0/1][0/1][0/1]为构造到第i位,第i-1位为j,第i位为k,第i-1位为是否为前导0,第i位是否为前导0,前i位是否与x的前i位一样
递归求会更好
code
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
ll f[21][11][11][2][2][2],a[19],b[19],n,m;
ll gets(ll x,ll i1,ll j3,ll i2,ll j2,ll full)
{
if (f[x][i1][j3][i2][j2][full]>0) return f[x][i1][j3][i2][j2][full];
ll bj,bz1,bz2;
if (x==a[0])
{
f[x][i1][j3][i2][j2][full]=1;
return f[x][i1][j3][i2][j2][full];
}
ll i,sum=0;
if ((full==1)||(x==0)) bj=a[x+1];else bj=9;
for (i=0;i<=bj;i++)
{
if (((i!=j3)||(j2==0))&&((i!=i1)||(i2==0)))
{
if (((full==1)||(x==0))&&(i==a[x+1])) bz1=1;else bz1=0;
if ((j2==0)&&(i==0)) bz2=0;else bz2=1;
sum+=gets(x+1,j3,i,j2,bz2,bz1);
}
}
f[x][i1][j3][i2][j2][full]=sum;
return sum;
}
ll get(ll n)
{
memset(f,0,sizeof(f));
if (n<0) return 0;
if (n<10) return n+1;
a[0]=0;
ll t;
while (n>0)
{
a[++a[0]]=n%10;
n/=10;
}
ll i;
for (i=1;i<=a[0]/2;i++)
{
t=a[i];
a[i]=a[a[0]-i+1];
a[a[0]-i+1]=t;
}
return gets(0,0,0,0,0,0);
}
int main()
{
freopen("numbers.in","r",stdin);
freopen("numbers.out","w",stdout);
scanf("%lld%lld",&n,&m);
ll ans=get(m);
ans-=get(n-1);
printf("%lld",ans);
}