HDU 3555 Bomb(数位DP)
题意:给一个n,问1-n多少个含有49的数字。
算是第一个数位DP吧,感觉数位DP只是通过数字之间的关系,写出状态转移方程的,看了别人的状态的转移,我以为我就可以做出来的,谁知,最后计算貌似比状态转移还难理解,至今不太明白为何要先+1,再计算,猜测可能是计算的时候只能计算1 - x-1的合法数字。
我所理解的计算的过程:如67995,先算出60000以内的再计算到67000之间的再计算67900再到67990,最后67995.
PS:为什么要+1呢,以下是我的猜测,试一下数据可以发现如果这个数里面没有存在‘49’,或者最后两位不是48,那么+1根本没有影响,这两种情况会导致最后的结果也会+1,因为前面计算的时候少算1,如4945,4*dp[3][2]+9*dp[2][2]+dp[2][1]....其实这样算会少一种情况,就是4900,最后要+1补回来。如果开始不+1,把代码的中的第43行的if中加上 sum++,计算上这个漏的情况,也可以AC。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 using namespace std; 6 #define ll __int64 7 ll dp[101][3]; 8 int p[101]; 9 int main() 10 { 11 int i,t,len,z; 12 ll sum,n; 13 scanf("%d",&t); 14 dp[0][0] = 1; 15 for(i = 1; i <= 19; i ++) 16 { 17 dp[i][0] = dp[i-1][0]*10 - dp[i-1][1]; 18 dp[i][1] = dp[i-1][0]; 19 dp[i][2] = dp[i-1][1]+dp[i-1][2]*10; 20 } 21 while(t--) 22 { 23 memset(p,0,sizeof(p)); 24 scanf("%I64d",&n); 25 n++; 26 sum = 0; 27 len = 1; 28 while(n >= 10) 29 { 30 p[len ++] = n%10; 31 n = n/10; 32 } 33 p[len] = n; 34 z = 0; 35 for( i = len; i>=1; i--) 36 { 37 sum += dp[i-1][2] * p[i]; 38 if(z) 39 sum += dp[i-1][0] * p[i]; 40 if(!z && p[i] >4) 41 sum += dp[i-1][1]; 42 if(p[i+1] == 4 && p[i] == 9) 43 z = 1; 44 } 45 printf("%I64d\n",sum); 46 } 47 return 0; 48 }