zoukankan      html  css  js  c++  java
  • AcWing1083 Windy数(数位dp)

    这题要求不含前导零,所以我们要对有前导0的数,进行枚举一遍

    前两题之所以可以用含前导零的来直接做,是因为不影响答案,比如度的数量,第一位选0没有问题

    又比如不降数问题,即使有前导0,也不影响答案,所以可以不处理

    但是对于windy数,会影响答案,比如一个数0135,按道理是135是符合答案的,但是加上前导0就不符合了,所以这题必须处理前导0

    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const int N = 35;
    
    int f[N][10];
    
    void init()
    {
        for (int i = 0; i <= 9; i ++ ) f[1][i] = 1;
    
        for (int i = 2; i < N; i ++ )
            for (int j = 0; j <= 9; j ++ )
                for (int k = 0; k <= 9; k ++ )
                    if (abs(j - k) >= 2)
                        f[i][j] += f[i - 1][k];
    }
    
    int dp(int n)
    {
        if (!n) return 0;
    
        vector<int> nums;
        while (n) nums.push_back(n % 10), n /= 10;
    
        int res = 0;
        int last = -2;
        for (int i = nums.size() - 1; i >= 0; i -- )
        {
            int x = nums[i];
            if (x)
            {
                for (int j = 1; j < x; j ++ )
                    if (abs(last - j) >= 2)
                        res += f[i + 1][j];
                if (i != nums.size() - 1)
                    if (abs(last - 0) >= 2)
                        res += f[i + 1][0];
            }
    
            if (abs(last - x) < 2) break;
            last = x;
    
            if (!i) res ++ ;
        }
    
        for (int i = 1; i < nums.size(); i ++ )
            for (int j = 1; j <= 9; j ++ )
                res += f[i][j];
    
        return res;
    }
    
    int main()
    {
        init();
    
        int l, r;
        cin >> l >> r;
    
        cout << dp(r) - dp(l - 1) << endl;
    
        return 0;
    }
    View Code

     下面的记忆化搜索,在理解上更加清晰

    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<cstring>
    using namespace std;
    const int N=20;
    int f[N][10][2][2];//前i位,前缀状态,是否还是最大值上界,有无前导0
    string l,r;
    string s;
    int len;
    int dfs(int cur,int x,int flag,int g){
        if(cur==len)
        return 1;
        if(f[cur][x][flag][g]!=-1)
        return f[cur][x][flag][g];
        int v=9;
        if(flag==1)
        v=s[cur]-'0';
        int ans=0;
        int i;
        for(i=0;i<=v;i++){
            if(g){
                if(!i)
                ans+=dfs(cur+1,0,flag&(i==v),1);
                else
                ans+=dfs(cur+1,i,flag&(i==v),0);
            }
            else{
                if(abs(i-x)>=2)
                ans+=dfs(cur+1,i,flag&(i==v),0);
            }
        }
        return f[cur][x][flag][g]=ans;
    }
    int solve(string t){
        s=t;
        len=t.size();
        memset(f,-1,sizeof f);
        return dfs(0,0,1,1);
    }
    int check(string t){
        int i;
        for(i=0;i<t.size()-1;i++){
            if(abs(t[i+1]-t[i])<2)
            return 0;
        }
        return 1;
    }
    int main(){
        memset(f,-1,sizeof f);
        cin>>l>>r;
        int ans=solve(r)-solve(l)+check(l);
        cout<<ans<<endl;
    }
    View Code
  • 相关阅读:
    24. orcle创建备份表
    23. oralce11g导出dmp然后导入Oracle10g
    模板
    日记集
    Outlook 2013 电子邮件账户设置备份与恢复
    Firefox恢复书签
    Windows 7 Professional安装多语言包
    CentOS下成功修复了Windows的grub引导
    CentOS 7修复MBR和GRUB
    从移动硬盘开机,引导VHD(Win10)
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12649960.html
Copyright © 2011-2022 走看看