hdu 3555 Bomb 炸弹(数位DP)

 

题意:给定一个数字n,求从1~n中有多少个数是含有49的,比如49,149,1490等都是含49的。

思路:数位DP。2^64也顶多是十进制的20多位,那么按十进制位来分析更简单。如果能计算1,2,3,4...位十进制数中分别有多少个含49的,那么计算就简单了。

首先要求关于十进制位的一些信息,比如:有i位的十进制数包含49有多少个,不包含49的多少个(除掉最高位是9的数量),不包含49但是最高位是9的有多少个(因为可能和更高一位组合成49)。

此题看别人详解吧,细节比较多。

 1 #include <bits/stdc++.h>

 2 #define LL long long

 3 using namespace std;

 4 const int N=22;

 5 LL dp[N][4];

 6 int s[25];

 7 

 8 void init()

 9 {

10     dp[0][0]=1;

11     for(int i=1; i<N; i++)

12     {

13         dp[i][0]=dp[i-1][0]*10-dp[i-1][1];  //dp[i][0]代表长度为 i 并且不含有49的数字的个数;

14         dp[i][1]=dp[i-1][0];                //dp[i][1]代表长度为 i 并且不含有49,但是最高位是9的数字的个数;

15         dp[i][2]=dp[i-1][1]+dp[i-1][2]*10; //dp[i][2]代表长度为 i 并且含有49的数字的个数。

16     }

17 }

18 

19 int main()

20 {

21     init();

22     freopen("input.txt", "r", stdin);

23     LL t, n;

24     cin>>t;

25     while(t--)

26     {

27         memset(s,0,sizeof(s));

28         scanf("%lld",&n);

29         int cnt=0;

30         n++;    //个位上必须大出1,方便计算出现紧挨着的49的情况。

31         while(n)

32         {

33             s[++cnt]=n%10;  //逐位提取出来

34             n/=10;

35         }

36         LL ans=0;

37         int last=0, flag=0;

38         for(int i=cnt; i>0; i--)    //具体就是要分析什么情况下会出现49,而且不能计算重复。

39         {

40             ans+=s[i]*dp[i-1][2];

41 

42             if(flag)    ans+=dp[i-1][0]*s[i];   //之前出现过紧挨着的49,那么第i位所可能出现的0~s[i]-1都与dp[i-1][0]个构成符合条件的数。

43 

44             if(!flag&&s[i]>4)    ans+=dp[i-1][1];   //s[i]大于4的情况,如果flag为true,那么都会在之前的紧挨49之后的那一步被统计掉。

45 

46             if(last==4&&s[i]==9)    flag=true;  //一旦flag开启,一直开启。目的是为了计算上限。

47 

48             last=s[i];

49         }

50         cout<<ans<<endl;

51     }

52     return 0;

53 }
AC代码

 

你可能感兴趣的:(HDU)