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 }

 

posted @ 2012-09-14 22:14  Naix_x  阅读(241)  评论(0编辑  收藏  举报