「解题报告」AGC009E Eternal Average

发布时间 2023-04-27 11:47:30作者: APJifengc

笑了,题意转换的思路大致都是对的,不知道为啥猜成与题解结论完全相反的结论了。

首先考虑将这个过程看做是一棵满 \(k\) 叉树,其中有 \(n + m\) 个叶子,\(n\) 个叶子为 \(0\)\(m\) 个叶子为 \(1\)。不难发现,如果一个 \(1\) 的深度为 \(x\),那么它对最后的数造成的贡献为 \(\frac{1}{k^x}\)

那么假如我们考虑 \(0, 1\) 的深度序列 \(\{x_i\}, \{y_i\}\),考虑什么样的序列能够对应到一颗树上。发现实际上就是如果把 \(0, 1\) 都算上贡献,最后和为 \(1\)。即:\(\sum \frac{1}{k^{x_i}} + \sum \frac{1}{k^{y_i}} = 1\)。证明考虑每次将次数最大的 \(k\) 个数进行合并,如果不能合并显然不可能等于 \(1\),于是一定可以通过这样的合并方式得到一棵合法的树。

那么我们相当于要统计满足上述的 \(\{x_i\}, \{y_i\}\) 序列中,有多少个不同的 \(\sum \frac{1}{k^{x_i}}\)。考虑将后面这个数写成 \(k\) 进制的形式,那么我们的问题就是对于一个序列 \(\{z_i\}\),能否将 \(\sum z_i k^i\) 表示成 \(\sum k^{x_i}\)。可以通过从高到低位依次满足的方式构造出一种方案,由于每次往下放一位造成的差值为 \(k-1\),那么只需要满足 \(\sum z_i \equiv n \pmod {k-1}\) 即可保证这个数一定可以被构造出来。

我们假设最终的数为 \(p\),那么我们一开始得出的条件实际上是要求:

  • \(p\) 能够被表示成 \(n\)\(\frac{1}{k^ {x_i}}\) 的加和;
  • \(1 - p\) 能够被表示成 \(m\)\(\frac{1}{k^ {y_i}}\) 的加和;

那么我们现在就可以将题意转换成统计有多少合法的长为 \(l\)\(\{z_i\}\) 序列,满足:

  • \(0 \le z_i < k\)
  • \(z_l \ne 0\)
  • \(\sum z_i \le n, \sum z_i \equiv n \pmod {k-1}\)
  • \(1 + \sum (k - z_i + 1) \le m, 1 + \sum (k - z_i + 1) \equiv m \pmod {k-1}\)

这个容易 DP 得出答案。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4005, P = 1000000007;
int n, m, k;
int f[MAXN][MAXN];
int main() {
    scanf("%d%d%d", &n, &m, &k);
    int ans = 0;
    for (int i = 0; i <= n; i++)
        f[0][i] = 1;
    for (int i = 1; i <= n + m; i++) {
        for (int j = max(0, (k - 1) * i - m + 1); j <= n; j++) {
            f[i][j] = (f[i - 1][j] - f[i - 1][max(0, j - (k - 1)) - 1] + P) % P;
            if ((j - n) % (k - 1) == 0)
                ans = (1ll * ans + 
                    f[i - 1][j - 1] - f[i - 1][max(0, j - (k - 1)) - 1] + P) % P;
            f[i][j] = (f[i][j] + f[i][j - 1]) % P;
        }
    }
    printf("%d\n", ans);
    return 0;
}