zoukankan      html  css  js  c++  java
  • CF908G New Year and Original Order

    首先我们难以计算每个在范围内的数对答案的贡献,注意到每个数的贡献组成是线性的,于是可以考虑计算每个数字对答案的贡献。

    那么你会发现对于数字 (d),当它在所选数中排名(从大到小)为 (i) 时对答案的贡献就为 (d imes 10 ^ {i - 1})

    那么现在的问题就转化为求数字 (d) 排在第 (i) 名的方案数。

    考虑一下 (d) 排在第 (i) 名的判定条件,不难发现是比 (d) 大的数字填的个数小于 (i),大于等于 (d) 的数字填了不少于 (i) 个。

    那么就有了一个暴力的 (dp),令 (dp_{i, j, k, l}) 表示当前考虑到第 (i) 位,当前数字 (j) 填了 (k) 个,当前大于 (j) 的数字填了 (l) 个的方案,不难发现复杂度是 (O(700 ^ 3 imes 10 ^ 2)) 的,还不足以通过本题。

    可以发现这个状态是无法优化的,优化转移也无济于事,那么只能回到原来的判定条件。

    不难发现这是由两个限制条件构成的,但第一种限制的反面实质上是第二种限制,于是可以考虑使用容斥来计算方案。

    那么我们要考虑的就是计算不小于 (d) 的数填了 (i) 个的方案数,不难发现这是可以直接使用数位 (dp) 做到 (O(700 ^ 2 imes 10 ^ 2)) 的。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i, l, r) for (int i = l; i <= r; ++i)
    const int N = 700 + 5;
    const int M = 10 + 5;
    const int Mod = 1e9 + 7;
    char s[N];
    int n, ans, a[N], p[N], dp[N][M][N][2], f[M][N];
    int read() {
        char c; int x = 0, f = 1;
        c = getchar();
        while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int Inc(int a, int b) { return (a += b) >= Mod ? a - Mod : a;}
    int Dec(int a, int b) { return (a -= b) < 0 ? a + Mod : a;}
    int Mul(int a, int b) { return 1ll * a * b % Mod;}
    int dfs(int p, int d, int s, bool limit) {
        if(s < 0) return 0;
        if(p > n) return !s;
        if(dp[p][d][s][limit] != -1) return dp[p][d][s][limit];
        int up = (limit ? a[p] : 9), ans = 0;
        rep(i, 0, up) ans = Inc(ans, dfs(p + 1, d, s - (i >= d), (limit & (i == up))));
        return dp[p][d][s][limit] = ans;
    }
    int main() {
        scanf("%s", s + 1), n = strlen(s + 1);
        rep(i, 1, n) a[i] = (s[i] - '0');
        memset(dp, -1, sizeof(dp));
        rep(i, 0, 9) rep(j, 0, n) dfs(1, i, j, 1);
        p[0] = 1;
        rep(i, 1, n) p[i] = Mul(p[i - 1], 10);
        rep(i, 0, 9) rep(j, 0, n) f[i][j] = Inc(max(0, dp[1][i][j][0]), max(0, dp[1][i][j][1]));
        rep(i, 1, 9) f[i][0] = Dec(f[i][0], 1); f[0][n] = Dec(f[0][n], 1);
        rep(i, 1, 9) rep(j, 1, n) {
            int tmp = 0;
            rep(k, j, n) tmp = Inc(tmp, Dec(f[i][k], f[i + 1][k]));
            ans = Inc(ans, Mul(tmp, Mul(i, p[j - 1])));
        }
        printf("%d", ans);
        return 0;
    }
    

    值得一提的是,当题目中存在两个限制时,如果一个限制的反面与另一个限制本质相同,往往可以使用满足一个条件另一个条件容斥计算来降低复杂度。

    另外,如果答案要求某个和或是线性的形式,往往可以分开考虑每一部分的贡献。

    GO!
  • 相关阅读:
    HDU 2844 Coins(多重背包)
    HDU 4540 威威猫系列故事——打地鼠(DP)
    Codeforces Round #236 (Div. 2)
    FZU 2140 Forever 0.5
    HDU 1171 Big Event in HDU(DP)
    HDU 1160 FatMouse's Speed(DP)
    ZOJ 3490 String Successor
    ZOJ 3609 Modular Inverse
    ZOJ 3603 Draw Something Cheat
    ZOJ 3705 Applications
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13800052.html
Copyright © 2011-2022 走看看