数位dp 入门 nbut 1475

来源:互联网 发布:做卡通人物的软件 编辑:程序博客网 时间:2024/05/08 20:01

nbut 1475

用dp[i][j][k]  表示滴i位时取j是已经有k个1 这样状态就很容易表示了

if(j==1) dp[i][j][k]=dp[i][0-9][k-1];

else dp[i][j][k]=dp[i][0-9][k];

统计的时候注意前面有个几个1;小心最大整数

#include<cstdio>#include<cstring>#include<iostream>#define M 12#define ll long longusing namespace std;int dp[M][M][M];void init(){    memset(dp,0,sizeof(dp));    dp[0][0][0]=1;    int n=10;    for(int i=0;i<M;i++){        for(int j=0;j<n;j++){            for(int k1=0;k1<M;k1++){                for(int k=0;k<n;k++){                    if(k==1){                        dp[i+1][k][k1+1]+=dp[i][j][k1];                    }                    else{                        dp[i+1][k][k1]+=dp[i][j][k1];                    }                }            }        }    }}int w[M];ll f(int n){    int len=0;    while(n){        w[++len]=n%10;        n/=10;    }    int flag=0;    ll tsum=0;    for(int i=len;i>=1;i--){        for(int j=0;j<w[i];j++){            for(int k=0;k<M;k++){                tsum+=dp[i][j][k]*(flag+k);            }        }        if(w[i]==1) flag++;    }    return tsum;}int main(){    int n;    init();    while(~scanf("%d",&n)){        if(n==2147483647){            puts("2971027783");            continue;        }        ll ans=f(n+1);        printf("%I64d\n",ans);    }    return 0;}