Digital + DP entry Detailed topics recommended

Unfinished, update tomorrow


Before we start, let's look at a question - topic Link

Subject requirements, the difference between two adjacent greater than or equal to 2, then we first construct a try.

For example, \ (15246 \) this number, let's take the first one to \ (1 \) , and then the second bit is \ (5 \) , \ (5-1 = 4> 2 \) so qualified, third bits are \ (2 \) , \ (5-2 = 3> 2 \) meet the conditions, the fourth bit is \ (4 \) , \ (4-2 = 2 \) meet the conditions, the fifth bit is \ ( 6 \) , \ (6-4 = 4 \) qualify, so the number of the qualifying.

So the question is, if we construct a number of a number, complexity is clearly a problem, we need to be optimized. View \ (15246 \) and \ (96,246 \) these two numbers, they are in line with the rules, but after they three are the same, then we can easily think of, as long as fourth from bottom with \ ( 2 \) poor compliance with the rules, as long as the three is \ (246 \) it must be in line with the rules, that is to say we do not need to repeat the judge.

There are no thoughts of familiar things? Yes, the memory of! Front to back configuration, when after several have been treated, we can use directly, rather than re-determine, saving time.

It is judged that it is very simple, just under an enumeration, look at the difference between the current position and meets the rules. Also requested topic does not contain leading zero, that is, except \ (0 \) any number other than their own are not allowed to use \ (0 \) at the beginning, then from the first beginning, we recorded a leading \ (0 \) when there is a not \ (0 \) Thereafter, the status is recorded without leading zeros, after the first non-zero leading zero bits without any limitation.

Then we look at the program it

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<cmath>
#define ll long long
#define gc() getchar()
#define maxn 15
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}
void write(ll a){
    if(a>9)write(a/10);
    putchar(a%10+'0');
}

int x,y,d[maxn],l;
ll f[maxn][maxn];
ll dfs(int pos,int pre,bool limit,bool lead){  //pos表示从后往前数第pos位,pre记录前一位我们选择的数值,limit记录当前是不是卡着最大值,如果卡着最大值就不能从[0,9]中任意选数,而是在[0,区间右端点当前位的数值]之间选数,lead就是记录前导零的问题了
    if(!pos)return 1;  //如果所有位都已经构造完了,说明这是一个合法数值,贡献加一
    if(!limit&&!lead&&~f[pos][pre])return f[pos][pre];  //如果已经处理过特殊要求均相同的情况,直接返回答案,避免重复计算
    int up=limit?d[pos]:9;ll ans=0;  //up就是当前位选数的右端点
    for(int i=0;i<=up;++i){  //枚举构造
        if(abs(i-pre)<2&&!lead)continue;  //如果不合法则跳过
        ans+=dfs(pos-1,i,limit&&i==d[pos],lead&&!i);
    }
    if(!limit&&!lead)f[pos][pre]=ans;  //这里有多种写法,其实就是要求你把各种特殊状态都记录下来
    return ans;
}

ll solve(int k){
    l=0;
    while(k){  //这里是为了记录一下当前范围最大是几位
        d[++l]=k%10;
        k/=10;
    }
    return dfs(l,0,1,1);
}

int main(){memset(f,-1,sizeof f);
    x=read();y=read();
    write(solve(y)-solve(x-1));  //答案要求是[x,y]之间的windy数,所以减去[0,x)的windy数即可
    return 0;
}

Guess you like

Origin www.cnblogs.com/hanruyun/p/11454535.html