M - windy数 数位dp

M - windy数

这个数位dp还比较明显,而且也比较好写,不过还是被我写搓了,伤心ing

这个数位dp,就是dp这个状态需要好好想想,还有就是这个前导0的问题,这个就是需要认真看题目。

我开始直接定义的一维dp,dp[i]定义为i位个数满足条件的数有多少

但是这个状态定义的是不完整的,因为第i位可以是1,2,3,4.。。。

这样子就不对了,所以一维是不够的,需要二维。

dp[i][j]表示有i位数,且最高位是j的满足条件的数有多少。

这个状态定义完之后就是前导0的处理了,我一开始以为这个可以不用判断前导0,但是实际上这个是需要判断前导0的

因为如果有前导0,那么这个数就可以随意放,但是如果没有就必须和前面的数进行比较,

所以这个还是要进行前导0 的判断的,如果你不进行前导0的判断,那这个代码就会写的很麻烦,而且还不一定写对。

我们先假设pre==-2因为abs(0-(-2))>=2这个意思就是说如果有前导0 就是对的,可以自行理解一下代码。

扫描二维码关注公众号,回复: 6303377 查看本文章
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
#include <iostream>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1010;
typedef long long ll;
ll dp[100][20];//前面i个数满足条件的数有多少
int a[maxn];

ll dfs(int pos,int pre,bool limit,bool lead)
{
    if (pos == -1) return 1;
    if (!limit &&!lead &&dp[pos][pre] != -1) return dp[pos][pre];
    int up = limit ? a[pos] : 9;
    ll ans = 0;
    for(int i=0;i<=up;i++)
    {
        if (abs(i - pre) < 2) continue;
        int p = i;
        if (lead&&i==0) p = -2;
        ans += dfs(pos - 1, p, limit && (i == up), p == -2);
    }
    if (!limit&&!lead) dp[pos][pre] = ans;
    return ans;
}

ll solve(int x)
{
    int pos = 0;
    while(x)
    {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos - 1, -2, 1, 1);
}

int main()
{
    int l, r;
    memset(dp, -1, sizeof(dp));
    while(scanf("%d%d",&l,&r)!=EOF)
    {
        ll ans = solve(r);
        ll ana = solve(l - 1);
        cout << ans - ana<< endl;
    }
    return 0;
}
数位dp

猜你喜欢

转载自www.cnblogs.com/EchoZQN/p/10945951.html