复制代码

数位DP入门

数位DP入门(蒟蒻)

概念
所谓数位DP就是指的数位DP,就是对数字的每一位进行DP 。
我们在具体例题中来分析数位DP

P2657 SCOI2009windy数

题目描述
不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。windy 想知道,在 a 和 b之间,包括 a 和 b ,总共有多少个 windy 数?
输入格式
输入只有一行两个整数,分别表示 a 和 b
输出格式
输出一行一个整数表示答案。
输入1

1 10

输出1

9

输入2

25 50

输出2

20

分析
我们将n的每一位拆分开分别计算它的贡献,从最高位依次固定,设
f[i][j] 表示一共i位,最高位是j的windy数的个数

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 11;
int f[N][10];//f[i][j] 表示一共i位,最高位是j的windy数个数
void init()
{
    for(int i=0;i<=9;i++) f[1][i] = 1;//个位数可以取10个
    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 l,r;
int dp(int n)
{
    if(n == 0) return 0;
    vector<int> v;
    while(n) v.push_back(n % 10),n /= 10;//提取每一位
    int res = 0;
    int last = -2;
    for(int i=v.size()-1;i>=0;i--)
    {
        int x = v[i];
        for(int j = i == v.size() - 1;j < x; j++)
        {
            if(abs(j - last) >= 2)
            res += f[i+1][j];
        }
        if(abs(x - last) >= 2) last = x;
        else break;
        if(i == 0) res++;
    }
    for(int i=1;i<v.size();i++)
    for(int j=1;j<=9;j++)
    res += f[i][j];
    return res;
}
int main()
{
    init();
    cin>>l>>r;
    cout<<dp(r) - dp(l - 1);
    return 0;
}

posted @ 2021-10-07 21:16  Elgina  阅读(50)  评论(0)    收藏  举报