您的位置:首页 > 其它

JZOJ5379. 【NOIP2017提高A组模拟9.21】Victor爱数字

2017-09-22 22:43 471 查看

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');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划