数位dp(Balanced Numbers )

题意:一个数,如果满足奇数的数字出现偶数次,偶数的数字出现奇数次,

就是符合的数,注比如:12313  就满足,因为1 3出现了偶数次。2出现了奇数次

思路,对于这道题,就是状态压缩加dp;

对于一个数字来说,0~9每一位,都只有3种状态量,要么从未出现,要么出现次数为奇

要么为偶,所以可以用3进制来表示,通过3进制表示出其状态,然后到pos-1的时候

判断0~9的各个状态是否符合条件即可

 1 #include<cstdio>
 2 #include<string.h>
 3 using namespace std;
 4 typedef long long ll;
 5 ll dp[20][60000];
 6 ll a[20];
 7 int check(int s)
 8 {
 9     for(int i=0;i<=9;++i){
10         int k=s%3;
11         s/=3;
12         if(k==0) continue;
13         else if((i&1)&&k==1)  return 0;  //若为奇数,如果出现次数也为奇,则退出;
14         else if(!(i&1)&&k==2) return 0;  //若为偶数,。。。。。。。。。。。。。。
15     }
16     return 1;
17 }
18 //三进制代码;
19 int change(int d,int s)
20 {
21     int temp[12];
22     for(int i=0;i<=9;i++){
23         temp[i]=s%3;
24         s/=3;
25     }
26     s=0;
27     if(temp[d]==0) temp[d]=1; //表示其状态的代码
28     else temp[d]=3-temp[d];   //表示其状态的代码
29     for(int i=9;i>=0;i--)
30         s=s*3+temp[i];
31     return s;
32 }
33 
34 ll dfs(ll pos,ll sum,bool flag,bool limit)
35 {
36     //flag是判断前导0用的
37     if(pos==-1) return check(sum);
38     if(!limit&&dp[pos][sum]!=-1) return dp[pos][sum];
39     int up=limit? a[pos]:9;
40     ll ans=0;
41     for(int i=0;i<=up;i++)
42                        //如果之前一直都是0,i==0,则sum的值依旧等于0
43         ans+=dfs(pos-1,(flag==0&&i==0)? 0:change(i,sum),flag||i>0,limit&&i==a[pos]);
44     if(!limit) dp[pos][sum]=ans;               //如果i已经大于0,则再也没有前导0这一说法
45     return ans;
46 }
47 ll solve(ll x)
48 {
49     int pos=0;
50     while(x){
51         a[pos++]=x%10;
52         x/=10;
53     }
54     return dfs(pos-1,0,0,true);
55 }
56 int main()
57 {
58     int T;
59     scanf("%d",&T);
60     memset(dp,-1,sizeof(dp));
61     while(T--){
62         ll l,r;
63         scanf("%lld%lld",&l,&r);
64         printf("%lld\n",solve(r)-solve(l-1));
65     }
66     return 0;
67 }

猜你喜欢

转载自www.cnblogs.com/pangbi/p/11881433.html