【数位DP】[LOJ10163]Amount of Degrees

发现自己以前对数位DP其实一窍不通...

 

这题可以做一个很简单的转换:一个数如果在$b$进制下是一个01串,且1的个数恰好有k个,那么这个数就是合法的(刚开始没判断必定是01串,只判断了1的个数竟然有60pts,数据可真的水~)

这个结论显然成立,也不需要什么证明啦qaq~

 

然后数位DP就好了

 

转化为b进制后要么插1要么插0,$dp[x][cnt]$表示当前处理到第i为,已经有cnt个1的情况下

转移方程:

$$dp[x][cnt]=\sum dp[x-1][cnt+1](当前位为1)$$

$$dp[x][cnt]=\sum dp[x-1][cnt](当前位为0)$$

记忆化搜索就好了

 1 #include<bits/stdc++.h>
 2 #define writeln(x)  write(x),puts("")
 3 #define writep(x)   write(x),putchar(' ')
 4 using namespace std;
 5 inline int read(){
 6     int ans=0,f=1;char chr=getchar();
 7     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
 8     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
 9     return ans*f;
10 }void write(int x){
11     if(x<0) putchar('-'),x=-x;
12     if(x>9) write(x/10);
13     putchar(x%10+'0');
14 }const int M = 50;
15 int dp[M][M],a[M],tp,l,r,x,y,k,b;
16 int dfs(int x,int cnt,int lim){
17     if(cnt>k)return 0;
18     if(x==0)return cnt==k;
19     if(!lim&&dp[x][cnt]!=-1)return dp[x][cnt];
20     int ans=0,up=b-1;
21     if(lim)up=a[x];
22     for(int i=0;i<=up;i++){
23         if(i==1)ans+=dfs(x-1,cnt+1,lim&&(a[x]==i));
24         else if(!i)ans+=dfs(x-1,cnt,lim&&(a[x]==i));
25     }
26     if(!lim)dp[x][cnt]=ans;
27     return ans;
28 }
29 inline int Solve(int x){
30     int tp=0;
31     while(x){a[++tp]=x%b;x/=b;}
32     return dfs(tp,0,1);
33 }
34 int main(){
35     memset(dp,-1,sizeof(dp));
36     l=read(),r=read(),k=read(),b=read();
37     l=Solve(l-1);r=Solve(r);
38     writeln(r-l);
39     return 0;
40 }

 

posted @ 2019-09-23 22:14  zheng_liwen  阅读(184)  评论(0编辑  收藏  举报
/*去广告*/