zoukankan      html  css  js  c++  java
  • [动态规划][数位dp]不要62

    Problem Description

    杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
    杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
    不吉利的数字为所有含有4或62的号码。例如:
    62315 73418 88914
    都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
    你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
     
    Input
    输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
     
    Output
    对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
     
    Sample Input
    1 100 0 0
     
    Sample Output
    80

    思路:似乎可以暴力?稍微修改一下,假定n,m<1e12把;进行数位dp,设状态f[i][j]表示位数为i,最高位为j的所有数中满足题意的数有多少,则状态转移方程为:

    if(j==4)  f[i][j]=0

    else if(j!=6) f[i][j]=sum{f[i-1][k]}(k=0,1,2,3,4,5,...,9)

    else f[i][j]=sum{f[i-1][k] }(k=0,1,3,4,5,...,9)

    那区间[0,n)中满足题意的数就为sum{f[i][k]}(k=0~a[i]-1)(a[i]表示n的第i位数字),再减去其中包含的一些不吉利数的个数;

    AC代码1:

    #include <iostream>
    #include<cstdio>
    typedef long long ll;
    using namespace std;
    
    ll n,m;
    ll dp[15][15];
    
    void get_dp(){
      dp[0][0]=1;
      for(ll i=1;i<=12;i++){
        for(ll j=0;j<=9;j++){
            dp[i][j]=0;
            if(j==4) continue;
            else{
                for(ll k=0;k<=9;k++) dp[i][j]+=dp[i-1][k];
                if(j==6) dp[i][j]-=dp[i-1][2];
            }
        }
      }
    }
    
    ll len=0,a[15];
    void depart(ll x){
      len=0;
      while(x){
        a[++len]=x%10;
        x/=10;
      }
    }
    
    ll cal(ll x){
      depart(x);//将x的各个位拆开
      ll ret=0;
      for(ll i=len;i>=1;i--){
        if(i<len&&a[i+1]==4) break;
        if(i<len-1&&a[i+1]==2&&a[i+2]==6) break;
        for(ll j=a[i]-1;j>=0;j--){
            if(i==len) ret+=dp[i][j];
            else{
                if(!(a[i+1]==6&&j==2)) ret+=dp[i][j];
            }
        }
      }
      return ret;
    }
    
    int main()
    {
        while(scanf("%lld%lld",&n,&m)!=EOF&&(n||m)){
            get_dp();
            printf("%lld
    ",cal(m+1)-cal(n));
        }
        return 0;
    }

    AC代码2:(数位dp的dfs写法--实质是记忆化搜索,建议看一下这个教程:https://www.bilibili.com/video/av27156563?from=search&seid=6478279662422300327)

    #include<cstdio>
    #include<algorithm>
    typedef long long ll;
    
    ll n,m;
    ll dp[15][2];//dp[i][0]表示当第i+1位不为6时,i位数中吉利数的个数;dp[i][1]表示当第i+1位为6时,i位数中吉利数的个数
    ll digit[20];
    
    ll dfs(ll len,bool last_6,bool limit){
      if(len==0) return 1;
      if(!limit && dp[len][last_6]) return dp[len][last_6];
      ll sum=0;
      for(ll i=0;i<=(limit?digit[len]:9);i++){
         if(i!=4 && !(last_6&&i==2)) sum+=dfs(len-1,i==6,limit&&i==digit[len]);
      }
      if(!limit) dp[len][last_6]=sum;
      return sum;
    }
    
    ll solve(ll x){
      digit[0]=0;//用digit[0]代替了len
      while(x){
        digit[++digit[0]]=x%10;
        x/=10;
      }
     return dfs(digit[0],false,true);
    }
    
    int main(){
      while(scanf("%lld%lld",&n,&m)&&(n+m)) printf("%lld
    ",solve(m)-solve(n-1));
      return 0;
    }
    转载请注明出处:https://www.cnblogs.com/lllxq/
  • 相关阅读:
    84. Largest Rectangle in Histogram (Solution 2)
    84. Largest Rectangle in Histogram (Solution 1)
    73. Set Matrix Zeroes
    【JavaScript】Symbol 静态方法
    【JavaScript】Date
    【JavaScript】Math
    725. Split Linked List in Parts把链表分成长度不超过1的若干部分
    791. Custom Sort String字符串保持字母一样,位置可以变
    508. Most Frequent Subtree Sum 最频繁的子树和
    762. Prime Number of Set Bits in Binary Representation二进制中有质数个1的数量
  • 原文地址:https://www.cnblogs.com/lllxq/p/9426701.html
Copyright © 2011-2022 走看看