标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4911 Accepted Submission(s): 2816
今天艾教讲了数位DP,自己硬着头皮写,竟然AC了,开心。
数位DP,dp[i][k]这两维是当前枚举到i,k是与给定的数比较,如果前i个数,正好等于给定的数,那么就是k就是1,否则就是0.举个栗子,比如给的最大的是236789.现在枚举到第三位6,如果前两个数是23,那么k=1,否则等于0. 然后对于本题还需两维,一维表示余数0-12,一维表示前面是否有13 d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0) d =2表示前面已经有13了,d=1表示前面只有1,0表示其他。
初始化dp[0][0][1][0] = 1,对于这个,晚上我和翔哥讨论了一下午,为什么初始化这个dp[0][0][1][0],或者为什么初始化1.最后对所有dp[n]的数求和,比如给的数是1300,那么求和后得到是1301,数位dp把1300分成了许多集合,满足这个条件的在一个集合,满足那个条件的在那个集合。为什么多一,翔哥自己迷迷糊糊的在分析,我也听的迷迷糊糊,如果有大神路过,希望留下解释,谢谢!
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int mod = 13; int dp[15][15][3][4]; char s[20]; int mi[15]; int cal(int x,int wei,int p) { return x*mi[wei]%p; } int main() { mi[0]=1; for (int i=1;i<=13;i++) mi[i]=mi[i-1]*10%13; while(scanf("%s",s)!=EOF) { int n = strlen(s); memset(dp,0,sizeof(dp)); dp[0][0][1][0] = 1; for(int i=0;i<n;i++) { for(int j=0;j<=12;j++) { for(int k=0;k<=1;k++) { for(int d=0;d<=2;d++) { if(dp[i][j][k][d]!=0) { int l = 0; int r = (k==1)?s[i]-‘0‘:9; for(int p=l;p<=r;p++) { dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:(((d==1||d==0)&&p==1)?1:0))] += dp[i][j][k][d]; /* if((i+1==4&&(j+cal(p,n-i-1,13))%13==0&&((k==1&&p==r)?1:0)==1&&(d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)))==2)||(i+1==4 && (j+cal(p,n-i-1,13))%13==0 && ((k==1&&p==r)?1:0==0) &&(d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)))==2)) printf("dp[%d][%d][%d][%d] = %d\n",i+1,(j+cal(p,n-i-1,13))%13,(k==1&&p==r)?1:0,d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)),dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0))]);*/ // printf("%d dp[%d][%d][%d][%d] = %d dp[%d][%d][%d][%d] = %d\n", p,i,j,k,d,dp[i][j][k][d],i+1,(j+cal(p,n-i-1,13))%13,(k==1&&p==r)?1:0,d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)),dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0))]);//*/ } } } } } } /* int ans = 0; for(int i = 0; i < 13; i ++) for(int j = 0; j < 2; j++) for(int k = 0; k < 3; k++) ans+=dp[n][i][j][k];*/ printf("%d\n",dp[n][0][1][2]+dp[n][0][0][2]); //printf("%d\n",ans); } return 0; }
标签:
原文地址:http://www.cnblogs.com/littlepear/p/5747763.html