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 }