HDU 3652 B-number
2016-01-28 18:35
232 查看
数位DP
dp[i][j][k][m]表示最高位为i,数字j在首位,之前是否出现过13,余数是m的情况下的个数
代码有详细注释,做完这题,感觉逐渐了解了数位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; }
相关文章推荐
- 配置python2.7开发环境
- HDU-ACM-2016
- 【开源中国Android客户端】源码分析(一) 启动
- Swift cell滑动数据丢失,图片重叠,cell重用问题的解决
- 微软Remote Modern IE 访问
- AngularJS 学习笔记
- alertify、js、css 使用简介
- 驱动中使用栈内存的问题
- iSCSI存储服务器
- python小记-一款不错的编译器
- 修改终端下vim的PopupMenu选种项的背景颜色
- SVN clean失败解决方法
- pow函数
- Zoo
- Xcode7.1与iOS9出现的异常bug
- Android 中dp,px,dpi以及sp的区别
- ViewPager Indicator的tab数据来自网络出现找不到viewPager的错误
- 测量函数的运行时间
- FTxxx系列-----------修改dclick的初始值
- 安卓开发-Activity中finish() onDestroy() 和System.exit()的区别