51nod1251 fox序列的数量(生成函数)
题目大意
一个不下降的序列被称为 Fox 序列,当且仅当序列里边出现频率最高的元素是唯一的。
例如:序列 1, 1, 2, 3, 4 是一个 Fox 序列, 因为它符合定义。出现频率最高的元素是1,它出现了2次,并且没有别的元素出现的次数为2。
但是序列 1, 1, 2, 2 不是 Fox 序列, 因为1 和 2 都出现了2次,不是唯一的。
注意: 序列 2, 1, 1 不是 Fox 序列, 因为他不是不下降序列。
给出N,M,计算有多少个长度为N的 Fox 序列,满足序列的所有元素都 >= 1并且 <= M。由于结果很大,输出Mod 1000000007的结果。
例如:N = 3,M = 2。满足条件的序列为:1 1 1, 2 2 2, 1 1 2, 1 2 2,共4个。
数据范围
第1行:一个数T,表示输入的测试数量(1 <= T <= 20)
第2 - T + 1行:每行2个数,N和M,中间用空格分隔(1 <= N, M <= 10^5)
解题思路
生成函数简单题
首先写出答案式子
[Ans = sum_{i=1}^nm*[n](1+x+x^2+ cdots +x^{i-1})^{m-1}\
= sum_{i=1}^mm*[n]frac {(1-x^i)^{m-1}}{(1-x)^{m-1}}
]
考虑分式上部的第 (ik) 项的系数是 ((-1)^k{m-1 choose k}),分式下部的第 k 项系数是 ({k + m - 2choose m - 2})
暴力乘起来即可,复杂度是 (Theta(NlogN)) 的
代码
const int P = 1e9+7;
const int N = 1005000;
const int lim = 200500;
ll inv[N], fac[N], T, m, n;
ll C(ll n, ll m) {
return fac[n] * inv[m] % P * inv[n-m] % P;
}
int main() {
inv[0] = fac[0] = inv[1] = fac[1] = 1;
for (int i = 2;i <= lim; i++)
inv[i] = inv[P % i] * (P - P / i) % P;
for (int i = 2;i <= lim; i++)
fac[i] = fac[i-1] * i % P,
inv[i] = inv[i-1] * inv[i] % P;
for (read(T); T; T--) {
read(n), read(m);
if (m == 1) { write(1); continue; }
ll ans = 0;
for (int i = 2;i <= n; i++) {
ll res = 0;
for (int j = 0;j * i <= n - i; j++) {
if (j & 1) res -= C(m - 1, j) * C(n - i - j * i + m - 2, m - 2);
else res += C(m - 1, j) * C(n - i - j * i + m - 2, m - 2); res %= P;
}
ans = (ans + res * m) % P;
}
write((ans + P) % P);
}
return 0;
}