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!
  • 相关阅读:
    理解Fragment生命周期
    嵌入式操作系统内存管理有哪几种,各有何特性
    laravel的auth用户认证的例子
    laravel验证器例子
    laravel加载js和css等资源
    laravel的blade模板的布局嵌套
    laravel的phpstorm插件laravel-ide-helper
    laravel开启调试模式
    laravel的中间件demo
    laravel路由定义
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13800052.html
Copyright © 2011-2022 走看看