【数位DP】SPOJ10606Balanced Numbers

来源:互联网 发布:淘宝模特拍照视频 编辑:程序博客网 时间:2024/05/18 03:19

传送门
题目大意:一个数被称为是平衡的数当且仅当对于所有出现过的数位,偶数出现奇数次,奇数出现偶数次。
给定AB,请统计出[A,B]内所有平衡的数的个数。

注意,这里的偶数是指出现过的数,并且不能计算前导零。蒟蒻一开始理解成所有的偶数和奇数,被坑成狗QAQ

对于每一个数有三种状态:
0:这个数还木有出现过。
1:这个数出现过奇数次。
2:这个数出现过偶数次。
于是乎用一个三进制数来表示每一种状态,然后直接转移吧…

窝写的是递推,但有些人说递推会T,不知道咋地反正窝交C++ (g++ 4.3.2)就是木有T。好像这题写记忆化搜索会快一些QAQ

蒟蒻分析应该是SPOJ的时间限制太无语辣,0.1s 23333
而记忆化搜索会在处理第二个cal()会快一些,毕竟第一次已经算了一些辣。

#include <iostream>#include <cstdio>#include <cstring>#define LL long long intusing namespace std;int p[15], cnt[10], w[20], len;LL f[30][60005][2];bool check(int j){    memset(cnt,0,sizeof cnt);    for(int i=0;j;++i, j/=3)        cnt[i]=j%3;    for(int i=0;i<10;++i)        if(cnt[i])        {            if(i&1)            {                if(cnt[i]&1)return 0;            }            else if(!(cnt[i]&1))return 0;        }    return 1;}LL cal(LL n){    if(!n)return 0;    memset(f,0,sizeof f);    LL m=n;    len=0;    while(m){w[++len]=m%10;m/=10;}    f[len][p[w[len]]][1]=1;    for(int i=len;i>0;--i)f[i][0][0]=1;    for(int i=w[len]-1;i>0;--i)        ++f[len][p[i]][0];    for(int i=len-1, s;i>0;--i)    {        for(int j=0;j<59049;++j)        {            if(!f[i+1][j][1]&&!f[i+1][j][0])continue;            for(int k=0;k<=9;++k)            {                if(!j&&!k)continue;//特殊处理前导零                s=j/p[k]%3+1;                s=s&1;                if(s==0)s=2;                s=j-j/p[k]%3*p[k]+s*p[k];                if(k==w[i])f[i][s][1]+=f[i+1][j][1];                else if(k<w[i])f[i][s][0]+=f[i+1][j][1];                f[i][s][0]+=f[i+1][j][0];            }        }    }    LL ans=0;    for(int j=1;j<59049;++j)        if(check(j))ans+=f[1][j][0]+f[1][j][1];    return ans;}int main(){    p[0]=1;    for(int i=1;i<=11;++i)p[i]=p[i-1]*3;    int cas;    LL a, b;    scanf("%d",&cas);    while(cas--)    {        scanf("%lld%lld",&a,&b);        printf("%lld\n",cal(b)-cal(a-1));    }    return 0;}
1 0
原创粉丝点击