1. 程式人生 > 實用技巧 >[BZOJ1026] windy數 - 數位dp

[BZOJ1026] windy數 - 數位dp

Description

\([a,b]\) 之間相鄰數位只差不超過 \(2\) 的數字個數。\(a,b \le 2\times 10^9\)

Solution

\(f[i][j][k]\) 表示從高到低走了 \(i\) 位,第 \(pos\) 位是 \(j\),且當前數字與 \(n\) 的關係為 \(k\)\(1\) 表示等於,\(0\) 表示小於)

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 25;

int f[N][N][N],a[N],n;

// 表示從高到低走完了第 i 位,第 i 位是 j,且當前數字與 n 的關係為 k(1 表示等於,0 表示小於)
int dfs(int i,int j,int k)
{
    if(~f[i][j][k]) return f[i][j][k];
    if(i==0) return f[i][j][k]=1;
    int lim = k?a[i-1]:9, ans = 0;
    if(j==-1)
    {
        for(int p=1;p<=lim;p++) ans+=dfs(i-1,p,p==lim);
    }
    else
    {
        for(int p=0;p<=min(j-2,lim);p++) ans+=dfs(i-1,p,k&&p==lim);
        for(int p=j+2;p<=lim;p++) ans+=dfs(i-1,p,k&&p==lim);
    }
    return f[i][j][k]=ans;
}

int solve(int val)
{
    memset(a,0,sizeof a);
    n=0;
    while(val)
    {
        a[n++]=val%10;
        val/=10;
    }
    memset(f,0xff,sizeof f);
    if(n==0) return 0;
    return dfs(n,-1,1);
}

int calc(int val)
{
    int ans = solve(val);
    int tmp = 1;
    while(tmp*10<=val) tmp*=10;
    --tmp;
    while(tmp)
    {
        ans += solve(tmp);
        tmp /= 10;
    }
    return ans;
}

signed main()
{
    ios::sync_with_stdio(false);

    int a,b;
    cin>>a>>b;
    --a;

    cout<<calc(b)-calc(a)<<endl;

    return 0;
}