zoukankan      html  css  js  c++  java
  • hdu 2089 不要62【数位dp】

    HDU 2089

    求给定区间内不含62和4的数的个数。

     数位dp入门。从这里我清楚了一些数位dp的用法。比如limit是判断是否达到上界,而且需要判断(!limit).。比如若题目要求不含11的个数,举例来说:区间在[1,215],当百位开始枚举为0时,十位枚举1,个位可以取0,2~9,即dp[0][1]=9,表示枚举到个位前一位为1时满足的个数,当然此时除了1都满足。而回溯枚举到百位为2,十位为1时,由于dp[0][1]已经枚举了,可以直接返回,但此时返回时有错误的,dp[0][1]=9,而百位为2,十位为1,个位是有限制的。所以记忆化判断是必须要有(!limit),否则会造成重复且答案错误。

    所以可以设计dp[pos][sta]表示枚举到第pos为状态为sta时的合法个数。sta指前一位是否为6,所以sta=0或sta=1。

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 int dp[20][2];
     5 int digit[20];
     6 
     7 int dfs(int pos,int pre,int sta,bool limit)
     8 {
     9     if(pos==-1) return 1;
    10     if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
    11     int up=limit?digit[pos]:9;
    12     int tmp=0;
    13     for(int i=0;i<=up;i++){
    14         if(pre==6&&i==2) continue;
    15         if(i==4) continue;
    16         tmp+=dfs(pos-1,i,i==6,limit&&i==digit[pos]);
    17     }
    18     if(!limit) dp[pos][sta]=tmp;
    19     return tmp;
    20 }
    21 
    22 int solve(int x)
    23 {
    24     int pos=0;
    25     while(x){
    26         digit[pos++]=x%10;
    27         x/=10;
    28     }
    29     return dfs(pos-1,-1,0,true);
    30 }
    31 
    32 int main()
    33 {
    34     int n,m;
    35     while(cin>>n>>m,!(n==0&&m==0))
    36     {
    37         memset(dp,-1,sizeof(dp));
    38         cout<<solve(m)-solve(n-1)<<endl;
    39     }
    40     return 0;
    41 }

    既然sta已包含前一位的信息,所以我觉得dfs时不记录pre也行。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 const int N=10;
     6 int dp[N][2];
     7 int digit[N];
     8 
     9 int dfs(int pos,int sta,bool limit)
    10 {
    11     if(pos==0) return 1;
    12     if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
    13     int up=limit?digit[pos]:9;
    14     int ans=0;
    15     for(int i=0;i<=up;i++){
    16         if(sta&&i==2) continue;
    17         if(i==4) continue;
    18         ans+=dfs(pos-1,i==6,limit&&i==digit[pos]);
    19     }
    20     if(!limit) dp[pos][sta]=ans;
    21     return ans;
    22 }
    23 
    24 int solve(int x)
    25 {
    26     int pos=0;
    27     while(x)
    28     {
    29         digit[++pos]=x%10;
    30         x/=10;
    31     }
    32     return dfs(pos,0,true);
    33 }
    34 
    35 int main()
    36 {
    37     int n,m;
    38     while(cin>>n>>m,!(n==0&&m==0))
    39     {
    40         memset(dp,-1,sizeof(dp));
    41         cout<<solve(m)-solve(n-1)<<endl;
    42     }
    43     return 0;
    44 }
  • 相关阅读:
    [BZOJ] 3191 [JLOI2013]卡牌游戏
    [LUOGU] P1466 集合 Subset Sums
    [LUOGU] P1113 杂物
    [BZOJ] 1003 [ZJOI2006]物流运输
    poj 2479 最大连续子段和
    C#学习第九弹之委托
    C#学习第八弹之线程基础理解
    C#学习第七弹之WPF
    hdu 2030 汉字的编码方式
    hdu 1559 暴力
  • 原文地址:https://www.cnblogs.com/zxhyxiao/p/7497296.html
Copyright © 2011-2022 走看看