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 }

 

你可能感兴趣的:(HDU)