笑了,题意转换的思路大致都是对的,不知道为啥猜成与题解结论完全相反的结论了。
首先考虑将这个过程看做是一棵满 \(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;
}
标签:le,frac,AGC009E,int,Average,Eternal,序列,sum,equiv
From: https://www.cnblogs.com/apjifengc/p/17358525.html