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
原文地址:https://www.cnblogs.com/ctyakwf/p/12649960.html