spoj 10606 数位dp统计

题目意思:

要求数字偶数数位出现基数次,基数数位出现偶数次,不出现,不违反规则。

状态压缩:3进制数 0表示未出现过 1表示出现基数次 2表示出现偶数次

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<cmath>
 7 using std::cin;
 8 using std::endl;
 9 using std::cout;
10 typedef long long LL;
11 int const N = 22;
12 int const M = 59050;
13 LL dp[N][M];
14 LL p3[N];
15 int bit[N],ln;
16 void pre()
17 {
18      p3[0]=1;
19      for(int i=1;i<=20;i++)p3[i]=p3[i-1]*3;
20 }
21 int deal(int s,int i)
22 {
23     int num=s/p3[i];
24     int p=num%3;
25     if(!p)p=1;
26     else
27       p=3-p;
28     s=s-(num%3)*p3[i]+p*p3[i];
29     return s;
30 }
31 bool sign(int s)
32 {
33      for(int i=0;s;i++,s/=3)
34      {
35          int pos=s%3;
36          if(pos==1&&i%2)return false;
37          if(pos==2&&!(i%2))return false;
38      }
39      return true;
40 }
41 LL getsum1(int t,int state,int limit,int zero)
42 {
43    if(!t)return sign(state);
44    int up=(limit?bit[t]:9);
45    if(!limit&&dp[t][state]!=-1)return dp[t][state];
46    LL ans=0;
47    for(int i=0;i<=up;i++)
48    {
49        if(zero&&i==0)
50        ans+=getsum1(t-1,state,limit&&i==up,zero&&i==0);
51        else
52        ans+=getsum1(t-1,deal(state,i),limit&&i==up,zero&&i==0);
53    }
54    if(!limit)dp[t][state]=ans;
55    return ans;
56 }
57 LL getsum2(LL n)
58 {
59    for(ln=0;n;bit[++ln]=n%10,n/=10);
60    return getsum1(ln,0,1,1);
61 }
62 int main()
63 {
64     memset(dp,-1,sizeof(dp));
65     pre();
66     int T;
67     scanf("%d",&T);
68     LL l,r;
69     while(T--)
70     {
71           scanf("%lld %lld",&l,&r);
72           l--;
73           printf("%lld\n",getsum2(r)-getsum2(l));
74     }
75     return 0;
76 }
View Code

 

posted @ 2013-05-22 15:39  诺小J  阅读(189)  评论(0编辑  收藏  举报