数位DP统计->Windy数(洛谷2657)

https://www.luogu.com.cn/problem/P2657

题意:给定范围,求windy数个数。windy数是相邻数字差值至少为2的数。

分析:前缀和差分,数位dp,从高到低判。
这里记录前导0的意义在于,如果前面都是0,那么前面的这一位可以看做是-2,在当前的pos位可以选任何数。
如果没有记录前导0,那么前面的数可能存在可能不存在,要按两种情况记录前面的数为-2或者其他。

void solve(){
    int l, r;
    cin >> l >> r;

    vector<int> num;
    vector<vector<int>> dp(11, vector<int>(11, -1));

    function<int(int, int, bool, bool)> dfs = [&](int pos, int pre, bool lead, bool limit){
        if (pos == 0){
            return 1;
        }
        if (!lead && !limit && dp[pos][pre] != -1){
            return dp[pos][pre];
        }
        int up = (limit == true ? num[pos] : 9);
        int res = 0;
        for (int i = 0; i <= up; ++i){
            if (abs(i - pre) >= 2){
                res += dfs(pos - 1, (lead && (i == 0)) ? -2 : i, lead && (i == 0), limit && (i == up));
            }
        }
        if (!lead && !limit){
            dp[pos][pre] = res;
        }
        return res;
    };

    auto cal = [&](int x){
        num.resize(1);
        while (x){
            num.emplace_back(x % 10);
            x /= 10;
        }
        return dfs(int(num.size()) - 1, -2, true, true);
    };

    cout << cal(r) - cal(l - 1) << '\n';
}
posted @ 2024-01-15 12:12  _Yxc  阅读(26)  评论(0)    收藏  举报