hdu2089不要62

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089

 

回来再写,赶去大物实验。。

-------------------------------------------------------------------------------

刚开始学数位dp,简单说一下自己的理解。

预处理部分先略过。。。

下面是转移阶段:

以n=84举例,看数位dp如何工作的。(针对本题,即求出不含4且不含62的数字个数)

对第一位8:

  如果取0--7,则肯定满足小于n,有bit[4]=8种选择。

  再考虑后面一位,dp[1][2]表示含4或62的一位数的个数(只有一个4),ans+d[1][2]*bit[4]; {74,64,54,44,34,24,14,04}共8种

  因为8>4,所以第一位可能取到4,当取4时,后面一位不论取什么都可以(为了不与上面的情况重复,限制后面的不能含有4或62)

  dp[1][0]表示不含4或者62的一位数,即ans+=dp[i-1][0];    {40,41,42,43,45,46,47,48,49}共9种

  因为8>6,所以第一位取6时,第二位可以取2.  再加上 ans+=dp[i-1][1];  {62},共1种

对第二位4, 所有情况均不满足,共0种。

所以一共有8+9+1=18个含4或62的数字,从分析可以看出求的是<84的范围,不含84。

 

好吧,我承认写的渣渣,,不过也理解了那么一丢丢

总的来说,就是从高位往低位进行,每完成一位就把该位固定,继续下一位。

分析每一位时都是从n向下取整(比如n=8000+,分析8时就是在分析0到7999),从而可以保证所有情况都小于n。

分析完后,固定该位(如上固定为8,继续分析下一位时,其实就是在分析8000到n),刚好不重复不遗漏。

 再简单分析一个  8653  (下面加号意义自己理解)

第一步:(0--7)+(000--999)

第二步: 8+(0--5)+(00--99)

第三步: 8+6+(0--4)+(0--9)

第四步:8+6+5+(0-2)

感觉这样写稍微好些。。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define ll long long
 4 int dp[11][3];
 5 int bit[11];
 6 int n,m;
 7 /*
 8 dp[i][0]  前i位没有不吉利数字
 9 dp[i][1]  前i位没有不吉利数字,但是第i位为2
10 dp[i][2]  前i位有不吉利数字
11 */
12 void init()
13 {
14     memset(dp,0,sizeof(dp));
15     dp[0][0]=1;
16     for(int i=1;i<11;i++)
17     {
18         dp[i][0]=dp[i-1][0]*9-dp[i-1][1];
19         dp[i][1]=dp[i-1][0];
20         dp[i][2]=dp[i-1][2]*10+dp[i-1][1]+dp[i-1][0];
21     }
22 }
23 int evil(int x)
24 {
25     int tmp=x;
26     int ans=0;
27     int len=0;
28     while(x)
29     {
30         bit[++len]=x%10;
31         x/=10;
32     }
33     bit[len+1]=0;
34     int flag=0;
35     for(int i=len;i;i--)
36     {
37         ans+=dp[i-1][2]*bit[i];
38         if(flag) ans+=dp[i-1][0]*bit[i];
39         else
40             {
41                 if(bit[i]>4) ans+=dp[i-1][0];
42                 if(bit[i+1]==6&&bit[i]>2) ans+=dp[i][1];
43                 if(bit[i]>6) ans+=dp[i-1][1];
44             }
45         if(bit[i+1]==6&&bit[i]==2||bit[i]==4) flag=1;
46     }
47     return tmp-ans;
48 }
49 int main()
50 {
51     init();
52     while(scanf("%d%d",&n,&m)&&(n||m))
53     {
54         printf("%lld\n",(ll)evil(m+1)-evil(n));
55     }
56 }

 

posted @ 2017-03-28 13:42  yijiull  阅读(123)  评论(0编辑  收藏  举报