数位DP
dp[i][j][k][m]表示最高位为i,数字j在首位,之前是否出现过13,余数是m的情况下的个数
代码有详细注释,做完这题,感觉逐渐了解了数位DP
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <map> #include <string> using namespace std; int dp[15][15][5][15]; int tot,n; int p[20]; bool cheak(int a,int b,int c,int d) { int res=a; for(int i=1;i<=b-1;i++) res=((res*10)%13); if((res+c)%13==d) return 1; return 0; } bool check2(int a,int b) { int num=0; for(int i=tot;i>=1;i--) { if(i>=a+1) num=num*10+p[i]; else num=num*10; } if((num%13+b)%13==0) return 1; return 0; } void init() { memset(dp,0,sizeof dp); for(int j=0;j<=9;j++) dp[1][j][0][j]=1; for(int i=2;i<=10;i++) { for(int j=0;j<=9;j++) { for(int k=0;k<=1;k++) { for(int l=0;l<=12;l++) { int sum=0; if(k==0)//推到第i位的时候都没有13 { for(int s=0;s<=9;s++)//枚举i-1位是多少 { if(j==1&&s==3) continue; for(int m=0;m<=12;m++)//枚举余数 if(cheak(j,i,m,l)) sum=sum+dp[i-1][s][0][m]; } dp[i][j][k][l]=sum; } else if(k==1)//推到第i位的时候有13,可能之前就有13,也可能i位和i-1位产生了13 { //之前就有13 for(int s=0;s<=9;s++) for(int m=0;m<=12;m++)//枚举余数 if(cheak(j,i,m,l)) sum=sum+dp[i-1][s][1][m]; //i位和i-1位产生了13 for(int s=0;s<=9;s++) if(j==1&&s==3)//这一位是1,上一位是3 for(int m=0;m<=12;m++)//枚举余数 if(cheak(j,i,m,l)) sum=sum+dp[i-1][s][0][m];//从之前没有13的情况推导过来 dp[i][j][k][l]=sum; } } } } } } int f(int x) { tot=1; while(x) { p[tot++]=(x%10); x=x/10; } tot--; int res=0; //计算位数比tot小的总和 for(int i=1;i<tot;i++) { for(int j=1;j<=9;j++) { res=res+dp[i][j][1][0]; } } //计算位数为tot,但首位比x首位小的数量总和 for(int i=1;i<p[tot];i++) res=res+dp[tot][i][1][0]; //计算剩余部分 bool flag=0; for(int i=tot-1;i>=1;i--) { for(int j=0;j<p[i];j++) { if(flag==0) { if(j==3&&p[i+1]==1) { for(int m=0;m<=12;m++) { if(check2(i,m)) { res=res+dp[i][j][0][m]; res=res+dp[i][j][1][m]; } } } else { for(int m=0;m<=12;m++) { if(check2(i,m)) { res=res+dp[i][j][1][m]; } } } } else if(flag==1) { for(int m=0;m<=12;m++) { if(check2(i,m)) { res=res+dp[i][j][0][m]; res=res+dp[i][j][1][m]; } } } } if(p[i]==3&&p[i+1]==1) flag=1;//表示之前已经出现过13了 } return res; } int main() { init(); while(~scanf("%d",&n)) printf("%d\n",f(n+1)); return 0; }
时间: 2024-10-12 19:16:57