HDU 不要62 题解

题目传送门

思路

数位 dp

数位 dp

数位 dp 模版题。

依次考虑每一位,满足题目给出的限制,统计数量,是一些较简单的数位 dp 题目的过程。

数位 dp 运用了差分的思想,即求 \(ans(l - r)\) 的答案用 \(ans(1 - r) - ans(1-(l - 1))\) 来表示.

对于本题,我们需要满足的性质很简单:

  1. 使数不超过上界,如求 \([5 - 1000]\) 不能使 \(1005\)
  2. 考虑到某一位时,如果其前一位为 \(6\),那么则一位不能为 \(2\),如果这一位填了 \(6\),下一位不能填 \(2\)
  3. 任何一位不能是 \(4\)

条件 1 是数位 dp 的常规操作,条件 2 和 条件 3 均可以在 dp 过程中通过检查标记来满足。

具体见代码。

代码

点击查看代码
/*
  --------------------------------
  |        code by FRZ_29        |
  |          code  time          |
  |          2024/08/11          |
  |           16:09:04           |
  |             星期天            |
  --------------------------------
                                  */

#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
#include <ctime>

using namespace std;

void RD() {}
template<typename T, typename... U> void RD(T &x, U&... arg) {
    x = 0; int f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    x *= f; RD(arg...);
}

const int N = 1e6 + 5, M = 10;

#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

int n, m, num[N];
int f[M][2][2];

int dfs(int u, bool lim, bool lim_6) { // lim 为条件 1 的限制,lim_6 为条件 3 的限制
    if (u == 0) return 1;
    if (f[u][lim][lim_6] != -1) return f[u][lim][lim_6]; // 记忆化搜索能优化时间复杂度
//    printf("u = %d, lim = %d, lim_6 = %d\n", u, lim, lim_6);
    int up = (lim ? num[u] : 9);
    f[u][lim][lim_6] = 0;
    LF(i, 0, up) {
        if (i == 4 || (lim_6 && i == 2)) continue;
        f[u][lim][lim_6] += dfs(u - 1, lim == true & i == up, i == 6);
    }
    return f[u][lim][lim_6];
}

int calc(int n) {
    if (n < 0) return 0;
    int tmp = n;
    int cnt = 0;
    while (tmp) num[++cnt] = tmp % 10, tmp /= 10;
    LF(i, 1, cnt) LF(j, 0, 1) LF(k, 0, 1) f[i][j][k] = -1;
    return dfs(cnt, 1, 0);
}

int main() {
    // freopen("read.in", "r", stdin);
    // freopen("out.out", "w", stdout);
    // time_t st = clock();
    while (RD(n, m), n, m) printf("%d\n", calc(m) - calc(n - 1));
    // printf("\n%dms", clock() - st);
    return 0;
}

/* ps:FRZ弱爆了 
 * 这是 FRZ 第 1 道数位 dp 题
 * FRZ做的太少了(悲
 * 真是弱爆了
 */

在逆风里把握方向,做暴风雨中的海燕,做不改颜色的孤星。

posted @ 2024-08-11 17:18  FRZ_29  阅读(6)  评论(0编辑  收藏  举报