spoj BLANNUM 数位状压dp

来源:互联网 发布:js特效代码 编辑:程序博客网 时间:2024/05/05 06:39

这题刚开始想的关系不对是因为没有考虑这个奇偶是相对于出现的数字来说的
所以dp[1024][1024][21][2] 一维代表出现的数字的状压形记录,二维表示出现数字奇偶的记录,三维代表推到第几位,四维代表是否有前导非零数
然后数位dp就行了

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cstring>#define LL long longusing namespace std;LL dp[1300][1300][21][2];LL l, x[100];LL dfs(int i, bool e, int sym1, int sym2, int sym3){   if(i == -1)   {      for(int j = 0; j <= 9; j++)          if((sym1 & (1<<j)) && ((j % 2 == 1 && (sym2 & (1 << j)))||(j % 2 == 0 && (sym2 & (1 << j)) == 0))) return 0;      return 1;   }   if(e && dp[sym1][sym2][i][!!sym3] != -1) return dp[sym1][sym2][i][!!sym3];   LL ans = 0;   int Max = e ? 9 : x[i];   for(int j = 0; j <= Max; j++)       ans += dfs(i - 1, !(!e && j == x[i]), (j||sym3)? (sym1|(1<<j)) : 0, (j||sym3)? (sym2^(1<<j)) : 0, sym3||j);   if(e) dp[sym1][sym2][i][!!sym3] = ans;   return ans;}LL cal(LL n){   l = 0;   while(n)   {      x[l++] = n % 10;      n /= 10;   }   return dfs(l - 1, 0, 0, 0, 0);}int main(){    memset(dp, -1 ,sizeof(dp));    int t;    scanf("%d", &t);    while(t--)    {        LL a, b;        scanf("%lld %lld", &a, &b);        printf("%lld\n", cal(b) - cal(a - 1));    }    return 0;}
0 0