BZOJ 1026: [SCOI2009]windy数 (数位dp dfs版本)

原题地址:https://www.lydsy.com/JudgeOnline/problem.php?id=1026
思路:这题要求不能有前导0,所以需要再加一维lead来控制前导0

记录一下我现在对于前导0的一些理解。

在dfs中,limit就是判断你当前这位数是否受到了遍历的上下界的影响,lead就是判断你当前这位数字前面是否有前导0(即前面是否全是0).那么在这道题中,很明显,如果你一位数前面没有前导0并且与它的差值 < 1 ,那么这就是不符合状态的,需要continue。如果你与前面的差值同样是 < 1 但是你有前导0(其实也可以理解为你当前这位数是位数最高的),比如说0100,第一位0其实是不存在的,只是为了方便统一形式,所以将前面一位数视为0.那么前面的01其实是合法的,因为1是最高位,他不能与前面的进行比较。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 4;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
int n, m, cnt;
int dp[100][10];//dp[i][j]表示处理第i位,前一位是数字j
//也可以开三维dp
int a[100];
int dfs(int pos, int pre,  bool limit, bool lead) {
    if(pos == -1) return 1;
    if(!limit && !lead && dp[pos][pre] != -1) return dp[pos][pre]; //lead 主要是在这里起作用
    int up = limit ? a[pos] : 9;
    int ans = 0;

    for(int i = 0; i <= up; i++) {//与下面的写法其实是一样的
        if(!lead && abs(i - pre) < 2) continue;
        ans += dfs(pos - 1, i, limit && i == up, lead && i == 0);
//    if(lead) {
//        for(int i = 0; i <= up; i++) {
//            ans += dfs(pos - 1, i, limit && i == up, lead && i == 0);
//        }
//    } else {
//        for(int i = 0; i <= up; i++) {
//            if(abs(pre - i) >= 2) ans += dfs(pos - 1, i, limit && i == up, 0);
//        }
//    }

        if(!limit && !lead ) dp[pos][pre] = ans; //lead 主要是在这里起作用
        return ans;
    }
    int solve(int x) {
        cnt = 0;
        while(x) {
            a[cnt++] = x % 10;
            x /= 10;
        }
        return dfs(cnt - 1,   -1, true, true);
    }
    int main() {
        memset(dp, -1, sizeof(dp));
        while(~scanf("%d%d", &n, &m)) {
            printf("%d\n", solve(m) - solve(n - 1));
        }
        return 0;
    }

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81128131