1. 程式人生 > 其它 >數位DP入門

數位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;
}