SPOJ BALNUM (数位DP+状压)

来源:互联网 发布:纬创软件 上海 编辑:程序博客网 时间:2024/05/18 18:18

用两个状态S,K

S中第i位为1,说明出现了奇数次,为0说明出现偶数次。

K中第i位为1,说明数字i出现过,为0说明没出现。

复杂度10的7次方。。。120ms跑过。。。


正解应该是用三进制把两个状态合并。


我的代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;typedef unsigned long long LL;LL a,b,dp[25][1<<10][1<<10];int bit[25],top;bool jud(int s,int k){    for(int i=0;i<10;i++){        if(k >> i & 1){            if((i & 1) && (s >> i & 1)) return false;            if(!(i & 1) && !(s >> i & 1)) return false;        }    }    return true;}LL dfs(int i,int s,int k,bool e,bool z){    //printf("%d %d %d\n",i,s,k);    if(i == -1) return k && jud(s,k) ? 1 : 0;    if(!e && dp[i][s][k] != -1) return dp[i][s][k];    LL res = 0;    int d , u = e ? bit[i] : 9;    for(d = 0;d <= u ;d++)        res += dfs(i-1,z&&(d==0) ? 0 : (s^(1<<d)),z&&(d==0) ? 0 : (k|(1<<d)),e&&(d==u),z&&(d==0));    return e ? res : dp[i][s][k] = res;}LL solve(LL n){    //printf("!!!!\n");    top = 0;    for(;n;n/=10) bit[top++] = (int)(n%10);    return dfs(top-1,0,0,1,1);}int main(){    int cas;    scanf("%d",&cas);    memset(dp,-1,sizeof(dp));    while(cas--){        scanf("%llu%llu",&a,&b);        printf("%llu\n",solve(b) - solve(a-1));    }    return 0;}


0 0