bzoj3134 [Baltic2013]numbers

来源:互联网 发布:帕尔哈提 知乎 编辑:程序博客网 时间:2024/06/06 21:39

题目链接:bzoj3134
题目大意:
一个数是非回文数当且仅当不包含长度大于1的回文数。比如16276是无回文数,而17276因为含有727而不是。
求区间内有多少个非回文数。

题解:
数位dp
在只做过一道数位dp的情况下居然自己打出来了还一A感动!
不过好像我要记录的东西有点多orz
因为他要求非回文数的个数,那么就是说填的时候不能跟前一位或者前两位填的数相同,于是就要记一下。然后忽然发现前导0什么的可能会误判,因为前导0不算进回文里,所以我用了两个布尔来存前两位分别是否为前导0.

LL dp(int i,int x,int y,bool zero1,bool zero2,bool edge)

i表示做到第几位,前两位填的分别是x、y,分别是否为前导0的状态为zero1、zero2,edge是判断是否在边界上。
然后对区间差分一下直接做就好了。
噢,初始状态那个edge要标记为true啊,我看了好久..为什么答案一直输出0..Orz

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;int lim[20];LL f[20][10][10][2][2][2];// 第i位,前两位分别是什么 分别是否为前导0 此时是否在边界上LL dp(int i,int x,int y,bool zero1,bool zero2,bool edge){    if (f[i][x][y][zero1][zero2][edge]!=-1) return f[i][x][y][zero1][zero2][edge];    if (i>lim[0]) return 1LL;    LL ans=0;    if (edge)    {        for (int j=0;j<lim[i];j++)         if ((zero1 || (x!=j)) && (zero2 || (y!=j)))            ans+=dp(i+1,y,j,zero2,zero2&(j==0),0);        if ((zero1 || (x!=lim[i])) && (zero2 || (y!=lim[i])))             ans+=dp(i+1,y,lim[i],zero2,zero2&(lim[i]==0),1);    }else    {        for (int j=0;j<=9;j++)         if ((zero1 || (x!=j)) && (zero2 || (y!=j)))          ans+=dp(i+1,y,j,zero2,zero2&(j==0),0);    }    return f[i][x][y][zero1][zero2][edge]=ans;}LL solve(LL x){    if (x<0) return 0;    lim[0]=0;    memset(f,-1,sizeof(f));    while (x) {lim[++lim[0]]=x%10;x/=10;}    for (int i=1;i*2<=lim[0];i++) swap(lim[i],lim[lim[0]-i+1]);    return dp(1,0,0,1,1,1);}int main(){    //freopen("a.in","r",stdin);    //freopen("a.out","w",stdout);    LL n,ans=0;    scanf("%lld",&n);n--;    ans-=solve(n);    scanf("%lld",&n);    ans+=solve(n);    printf("%lld\n",ans);    return 0;}
0 0