数位dp题集

来源:互联网 发布:用java写雷电x 小游戏 编辑:程序博客网 时间:2024/06/02 04:27

ural1057  论文题,b进制转二进制,按二进制数位dp,符合题意的应当满足每位为0或1,例如3*****,就相当于111111,因为2和3开头的数必然不满足条件,因此相当于区间[000000,111111].

#include<cstdio>#include<iostream>#include<cstring>using namespace std;int dp[40][30];int tot,bit[40];void change(int x,int b){    tot=0;    while(x){        bit[tot++]=x%b;        x/=b;    }    for(int i=tot-1;i>=0;i--)        if(bit[i]>1){            for(int j=0;j<=i;j++)                bit[j]=1;            break;        }}int cal(int k){    int ans=0;    for(int i=tot-1;i>=0;i--){        if(bit[i]){            ans+=dp[i][k];            if(--k<0) break;        }    }    return ans+!k;}int main(){    dp[0][0]=1;    for(int i=1;i<31;i++){        dp[i][0]=1;        for(int j=1;j<=i;j++)            dp[i][j]=dp[i-1][j]+dp[i-1][j-1];    }    int x,y,k,b,ans;    while(cin>>x>>y>>k>>b){        change(y,b);        ans=cal(k);        change(x-1,b);        ans-=cal(k);        cout<<ans<<endl;    }return 0;}


记忆化版:

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;int dp[40][40];int num[40];int tot;void change(int x,int b){    tot=0;    while(x){        num[tot++]=x%b;        x/=b;    }    for(int i=tot-1;i>=0;i--)        if(num[i]>1){            for(int j=0;j<=i;j++)                num[j]=1;            break;        }}int dfs(int cur,int s,bool flag){    if(s<0) return 0;    if(cur==-1) return s==0;    if(!flag&&dp[cur][s]>=0) return dp[cur][s];    int up=flag?num[cur]:1;    int ans=0;    for(int i=0;i<=up;i++)        ans+=dfs(cur-1,s-(i==1),flag&&i==up);    return flag?ans:dp[cur][s]=ans;}int main(){    int n,m,k,b;    memset(dp,-1,sizeof dp);    cin>>n>>m>>k>>b;    change(m,b);    int ans=dfs(tot-1,k,true);    change(n-1,b);    cout<<ans-dfs(tot-1,k,true)<<endl;return 0;}

未完...

0 0
原创粉丝点击