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
题解
很显然,这是数位dp。
将问题变为求1~r的减去1~(l-1)的。
如果不出现回文超过1的串,其实只需要判断是否存在
长度为1或者2的就可以了。
设
fi,s1,s2
表示当前是第i位,不存在前导0,末尾两位分别是s1,s2。
转移就枚举一个k,表示之前的那一位选了什么。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 150003
#define db double
#define P putchar
#define G getchar
#define mo 1000000007
using namespace std;
char ch;
void read(ll &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x)
{
if(x>9) write(x/10);
P(x%10+'0');
}
ll a,b,ans;
ll f[23][13][13];
ll work(ll x)
{
if(x<10)return x+1;
ll t[23],len=0,g=1;
while(x)
{
t[++len]=x%10;
x/=10;
}
for(int i=1;i<=len/2;i++)
swap(t[i],t[len-i+1]);
t[0]=10;t[len+1]=-123;
memset(f,0,sizeof(f));
//f[1][0][0]=1;
for(int i=1;i<=len;i++)
{
for(int s1=0;s1<10;s1++)
for(int s2=0;s2<10;s2++)
{
if(s1==s2)continue;
for(int k=0;k<=10;k++)
if(k!=s1 && k!=s2)f[i][s1][s2]+=f[i-1][k][s1];
}
/*if(i>1)
{
for(int k=0;k<10;k++)
f[i][10][k]++;
}*/
for(int k=i==1;k<t[i];k++)
if(t[i-1]!=k && t[max(i-2,0)]!=k)f[i][t[i-1]][k]+=g;
if(t[i]==t[i-1] || t[i-2]==t[i])g=0;
}
ll ans=g;
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
ans+=f[len][i][j];
return ans;
}
ll sum(ll x)
{
ll ans=work(x),t=10;
x/=10;
while(x>0)ans+=work(t-1),t*=10,x/=10;
return ans;
}
int main()
{
freopen("numbers.in","r",stdin);
freopen("numbers.out","w",stdout);
read(a);read(b);
printf("%lld",sum(b)-sum(a-1));
//while(1)read(a),write(sum(a)),P('\n');
}