首页 > 其他分享 >Windy数

Windy数

时间:2022-09-18 20:00:25浏览次数:77  
标签:pre nums int windy Windy 前导 size

数位DP

原题链接

题目描述:计算从[l,r]中windy数的个数
windy数:不含前导零且任意相邻两位数字之差至少为2

1083.Windy数.jpg
由于不含前导零,所以最高位不能从0开始,只能从1~x-1
考虑状态表示:
f[i][j]表示共有i位,且最高位为j的windy数的个数
状态转移:
f[i][j] += f[i - 1][k],其中abs(j-k)>=2

#include <iostream>
#include <cstring>
#include <vector>

const int N = 15;

// f[i][j]表示共有i位,最高位为j的windy数的个数
// 这里状态是包含前导零的
int f[N][10];

void init() {
    for (int i = 0; i <= 9; i ++ ) f[1][i] = 1;
    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 cal(int n) {
    if (!n) return 0;
    std::vector<int> nums;
    while (n) nums.push_back(n % 10), n /= 10;
    
    // 由于第一位可以随便放,所以保证对任意x∈ (0,9),abs(pre,x)都成立即可
    int res = 0, pre = -2;
    for (int i = nums.size() - 1; i >= 0; i -- ) {
        int x = nums[i];
        // 最高位不能从0开始枚举
        for (int j = i == nums.size() - 1; j < x; j ++ )
            if (abs(j - pre) >= 2) res += f[i + 1][j];
        if (abs(x - pre) < 2) break;
        pre = x;
        if (!i) res ++ ;
    }
    
    // 处理前导零的情况,也就是位数小于nums.size()的情况
    // 例如14本来是windy数,由于前导零的存在,014中01是不满足条件的
    // 所以f[3][0]会被筛掉,就会导致答案漏掉;
    // 存在前导零则至少有一位,且最高位不是0
    // 所以i从1开始,j也从1开始
    for (int i = 1; i < nums.size(); i ++ )
        for (int j = 1; j <= 9; j ++ )
            res += f[i][j];
            
    return res;
}

int main() {
    init();
    
    int l, r;
    std::cin >> l >> r;
    std::cout << cal(r) - cal(l - 1) << '\n';
    return 0;
}

标签:pre,nums,int,windy,Windy,前导,size
From: https://www.cnblogs.com/zjh-zjh/p/16705589.html

相关文章