题解 [SCOI2009]windy数

数位dp即可
定义\(f[i][j]\)\(i\)为数以\(j\)开头的符合条件的个数
状态转移方程\(f[i][j]=\sum_{k=0}^9f[i-1][k](\left|j-k\right|\ge2)\)
具体实现见代码

#include<bits/stdc++.h>
using namespace std;
int f[12][12] = {0};
int a,b;
int lena = 0,lenb = 0;
int ac[12],bc[12];
int ans = 0;
int cnt[12] = {0};
int main(){
    scanf("%d%d",&a,&b);
    b++;
    for(int i = 0;i<10;i++) f[1][i] = 1;
    int res = a;
    while(res){
        ac[++lena] = res%10;
        res/=10;
    }
    res = b;
    while(res){
        bc[++lenb] = res%10;
        res/=10;
    }
    ac[lena+1] = -19260817;
    bc[lenb+1] = -19260817;
    for(int i = 2;i<=lenb;i++){
        for(int j = 0;j<10;j++)
            for(int k = 0;k<10;k++) 
                if(abs(j-k)>=2)
                    f[i][j] += f[i-1][k];
        cnt[i] = cnt[i-1];
        for(int j =1;j<10;j++){
            cnt[i] += f[i-1][j];
        }
    }
    ans += cnt[lenb]-cnt[lena];
    bool flag = 0;
    for(int i = lenb;i;i--){
        for(int j = 0;j<bc[i];j++){
            if(i==lenb&&j==0) continue;
            if(abs(j-bc[i+1])>=2){
                ans += f[i][j];
            }
        }
        if(abs(bc[i]-bc[i+1])<2) break;
    }   
    for(int i = lena;i;i--){
        for(int j = 0;j<ac[i];j++){
            if(i==lena&&j==0) continue;
            if(abs(j-ac[i+1])>=2) ans -= f[i][j];
        }
        if(abs(ac[i]-ac[i+1])<2) break;
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LJA001100/p/11434549.html