hdu(3652)——B-number(数位dp)
2016-03-01 20:30
357 查看
题意:
让你求出1~N中含有13这个子串的并且能够被13整除的数有几个,并输出数量。
思路:
卡了好几天啊!!还是看了别人的题解才获得的思路。
本人一开始想的比较简单,就是记录一下乘出来的数字,然后在最后判断一下,但是我觉得我是在记忆化那里写错了,我记忆化保存的状态好像少了一维,所以导致最后错误代码输1000这个数据时是错误的答案,现在也没能想清楚要怎么修改自己的这个程序(貌似再加一维?)如果有大神愿意指教,那么真的十分感谢了= =
错误代码:http://paste.ubuntu.com/15258236/
别人思路很巧妙啊,看了一个下午才明白。。
首先我们设一个三维dp,dp[i][j][k],表示i位数,对13的余数为j,然后为k的满足条件k的且能被13整除的后序的数有几个。
k=0代表在i位之前已经出现了13这个数字了,然后求的是后面满足能被13整除的情况数。
k=1代表在i位之前没有出现13,但是i-1位是1,然后求的是当第i位是3,且后面能被13整除的情况数。
k=2代表在i位之前没有出现13且i-1位不是1,但是在后面出现了13且整个数能被13整除的数的个数。
总的来说这个dp比较抽象,我觉得应该好好理解一下。
详细的解释写在代码中了。
让你求出1~N中含有13这个子串的并且能够被13整除的数有几个,并输出数量。
思路:
卡了好几天啊!!还是看了别人的题解才获得的思路。
本人一开始想的比较简单,就是记录一下乘出来的数字,然后在最后判断一下,但是我觉得我是在记忆化那里写错了,我记忆化保存的状态好像少了一维,所以导致最后错误代码输1000这个数据时是错误的答案,现在也没能想清楚要怎么修改自己的这个程序(貌似再加一维?)如果有大神愿意指教,那么真的十分感谢了= =
错误代码:http://paste.ubuntu.com/15258236/
别人思路很巧妙啊,看了一个下午才明白。。
首先我们设一个三维dp,dp[i][j][k],表示i位数,对13的余数为j,然后为k的满足条件k的且能被13整除的后序的数有几个。
k=0代表在i位之前已经出现了13这个数字了,然后求的是后面满足能被13整除的情况数。
k=1代表在i位之前没有出现13,但是i-1位是1,然后求的是当第i位是3,且后面能被13整除的情况数。
k=2代表在i位之前没有出现13且i-1位不是1,但是在后面出现了13且整个数能被13整除的数的个数。
总的来说这个dp比较抽象,我觉得应该好好理解一下。
详细的解释写在代码中了。
#include<cstdio> #include<cstring> #include<map> #include<set> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<iostream> #include<time.h> using namespace std; typedef long long ll; typedef unsigned long long ULL; #define pi acos(-1.0) #define Ex exp(1.0) #define inf 99999999 #define maxn 22 int d[maxn],vis[maxn][maxn]; ll dp[maxn][maxn][3]; //分别表示当前考虑的位置,前一个数字,当前余数,是否有限制,是否已经出现13 ll go(int dep,int pre,int mod,int less,int flag){ if(dep<0) return (mod==0)&&flag; //如果已经出现了13,而且余数为0,返回1,否则为0 else if(less&&flag&&dp[dep][mod][0]!=-1) return dp[dep][mod][0]; //没有限制而且之前已经出现13,那么后面就随意 else if(less&&!flag&&pre==1&&dp[dep][mod][1]!=-1) return dp[dep][mod][1]; //之前没有13,但是末位是1,那么后面的高位可以是3 else if(less&&!flag&&pre!=1&&dp[dep][mod][2]!=-1) return dp[dep][mod][2]; else{ ll re=0; //代表没有限制 if(less){ for(int i=0;i<10;i++){ re+=go(dep-1,i,(mod*10+i)%13,1,flag||(pre==1&&i==3)); } if(flag) dp[dep][mod][0]=re; //这里的意思是求当已经出现了13(因为之前带过来的flag就是为1的,所以上面只要判断能否被13整除就好了) if(!flag&&pre==1) dp[dep][mod][1]=re; //这里的意思是当前面没有出现过13但是前一位pre=1时,有多少种方案数 if(!flag&&pre!=1) dp[dep][mod][2]=re; //这里的意思是当前面既没有出现过13而且前一位也不是1时,有多少种方案数,这里可以进行统一的求解。 return re; } //代表有限制 else{ for(int i=0;i<=d[dep];i++){ re+=go(dep-1,i,(mod*10+i)%13,i<d[dep],flag||(pre==1&&i==3)); } return re; } } } ll solve(ll x){ int len=0; while(x){ d[len++]=x%10; x=x/10; } return go(len-1,-1,0,0,0); } int main(){ ll n; memset(dp,-1,sizeof(dp)); while(~scanf("%I64d",&n)){ printf("%I64d\n",solve(n)); } #ifndef ONLINE_JUDGE system("pause"); #endif return 0; }
相关文章推荐
- 三维漫游飞行路径建立方法与插值算法
- 十九个国内外主流的三维GIS
- 【HDU 5366】The mook jong 详解
- 【HDU 2136】Largest prime factor 详细图解
- HDU 1568
- HDU1290
- HDU1568(Fobonacci公式)
- HDU ACM Step 2.2.2 Joseph(约瑟夫环问题)
- HDU 1405
- HDU 1297
- hdu 1205
- hdu 2087
- hdu 1016
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- HDU 5592 ZYB's Premutation 线段树(查找动态区间第K大)
- HDU 5240 Exam (好水的题)
- HDU5237 Base64 大模拟
- HDU 1000
- HDU 1001
- 欢迎使用CSDN-markdown编辑器