zoukankan      html  css  js  c++  java
  • 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
    ",(ll)evil(m+1)-evil(n));
    55     }
    56 }
  • 相关阅读:
    cf914D. Bash and a Tough Math Puzzle(线段树)
    RNQOJ [stupid]愚蠢的矿工(树形依赖背包)
    BZOJ4552: [Tjoi2016&Heoi2016]排序(线段树 二分)
    多项式系数学习笔记
    BZOJ4653: [Noi2016]区间(线段树 双指针)
    洛谷P3372 【模板】线段树 1(树状数组)
    BZOJ3261: 最大异或和(可持久化trie树)
    BZOJ4260: Codechef REBXOR (01Tire树)
    Android 关于显示键盘,布局错乱网上顶的问题
    Java 输入流读取文本文件换行符问题
  • 原文地址:https://www.cnblogs.com/yijiull/p/6634156.html
Copyright © 2011-2022 走看看