刚开始接触数位dp,看其他的博客和教程也不是很懂,不过学习就是一个循序渐进的过程嘛๑乛◡乛๑
下面简单写写入门级的hdu2089不要62
中途找到一个比较好的ppt,我觉得讲的还是很清楚的了->初探数位dp
(下面的过程咋一看不明白可以把中间的过程打印出来,我是这样做的,感觉初学很见效)
1、预处理
dp[i][j]代表首位为j的i位数里符合条件(不含62和4)的数的个数
提前都算出来,在下一步可以直接用(数组开销也不大,本题中[7][10]足够了)
比如dp[3][0]代表的就是000~099之间符合条件的数,dp[3][1]代表100~199之间的数...
2、计算
统计区间[left,right]的个数可以看作[0,right]-[0,left)
可以设想把一个数分成不同范围的数的集合并集
比如321可以看作[0,99]+[100,199]+[200,299]+[0,9]+[10,19]+[0,1],即dp[3][0]+dp[3][1]+dp[3][2]+dp[2][0]+d[2][1]+dp[1][0]+dp[1][1]
用digit[i]表示从右到左第i位上的数
如果在循环的时候遇到4或者62则停止计算(循环是从高位到低位算的,4和62往后的低位都不用考虑了)
动手做做想的更快些(•‾̑⌣‾̑•)✧˖°
#include <iostream> using namespace std; int dp[10][10] = {0}; void init() { int i,j,k; for(i = 0; i <=9; ++i) dp[1][i] = 1; dp[1][4] = 0; for(i = 2; i <= 6; ++i) { for(j = 0; j <= 9; ++j) { if(j==4)continue; for(k = 0; k <= 9; ++k) { if(k!=4&&!(j==6&&k==2)) dp[i][j] += dp[i-1][k]; } } } } /* void soutInit(){ for(int i=0;i<=6;++i){ for(int j=0;j<=9;++j){ cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<endl; } } }*/ int solve(int n) { int i,j,k,digit[10]; int len = 0,ans = 0; while(n!=0) { digit[++len] = n%10; n/=10; } digit[len+1] = 0; for(i = len; i > 0; --i) { for(j = 0; j < digit[i]; ++j) { if(j==4 || (digit[i+1]==6 && j == 2))continue; ans += dp[i][j]; //cout<<"dp["<<i<<"]["<<j<<"]"<<" "; } if(digit[i]==4||(digit[i]==2&&digit[i+1]==6))break; } return ans; } int main() { init(); //soutInit(); int l,r; while(cin>>l>>r){ if(l==0&&r==0){ break; } cout<<solve(r+1)-solve(l)<<endl; } return 0; }
最后皮一下:
单说这道题的话,其实想过用字符串检测是否包含“62”或者“4”的,然后。。。TLE了(,,Ծ‸Ծ,,)