Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4559
Solution
由容斥原理得:
ans=∑i=Kmin{N−1−R}(−1)i−KCKiCiN−1∏j=1MCN−Rj−iN−1−i∑x=1UixN−Rj(Uj−x)Rj−1
a
n
s
=
∑
i
=
K
min
{
N
−
1
−
R
}
(
−
1
)
i
−
K
C
i
K
C
N
−
1
i
∏
j
=
1
M
C
N
−
1
−
i
N
−
R
j
−
i
∑
x
=
1
U
i
x
N
−
R
j
(
U
j
−
x
)
R
j
−
1
这么长的式子,一项一项地进行解析:
(1) ∑min{N−1−R}i=K(−1)i−KCKi ∑ i = K min { N − 1 − R } ( − 1 ) i − K C i K :求「恰好完虐 K K 个同学」时乘上容斥系数。
(2) :在 N−1 N − 1 个同学中选出 i i 个同学被完虐。
(3) :把每一科分开处理之后相乘。
(4) CN−Rj−iN−1−i C N − 1 − i N − R j − i :在没有被完虐的 N−1−i N − 1 − i 个同学中,选出 N−Rj−i N − R j − i 个同学,让他们第 j j 课被虐。
(5) :枚举 B 神第 j j 科成绩。
(6) :第 j j 科被虐的同学的成绩方案数。
(7) :第 j j 科没有被虐的同学的方案数。
显然,我们要处理的关键在于 及之后的式子。
发现 (Uj−x)Rj−1 ( U j − x ) R j − 1 不好处理。
考虑无脑展开:
∑x=1UixN−Rj∑k=0Rj−1(−1)kxkURj−1−kj
∑
x
=
1
U
i
x
N
−
R
j
∑
k
=
0
R
j
−
1
(
−
1
)
k
x
k
U
j
R
j
−
1
−
k
=∑k=0Rj−1(−1)kURj−1−kj∑x=1UixN−Rj+k
=
∑
k
=
0
R
j
−
1
(
−
1
)
k
U
j
R
j
−
1
−
k
∑
x
=
1
U
i
x
N
−
R
j
+
k
注意到 ∑Uix=1xN−Rj+k ∑ x = 1 U i x N − R j + k 是以 x x 为自变量的 次多项式,上拉格朗日插值法即可求得。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 111, ZZQ = 1e9 + 7;
int pwe[N][N], y[N], qaq[N], tmp[N], rps[N], inv[N], com[N][N],
C[N][N], n, m, K, U[N], R[N], ans, czk[N];
int qpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = 1ll * res * a % ZZQ;
a = 1ll * a * a % ZZQ;
b >>= 1;
}
return res;
}
void lagrange(int n) {
int i, j;
For (i, 1, n + 2)
y[i] = (y[i - 1] + pwe[i][n]) % ZZQ;
qaq[0] = 1;
For (i, 1, n + 2) {
tmp[0] = qaq[i] = 0;
For (j, 0, i - 1) tmp[j + 1] = qaq[j];
For (j, 0, i)
qaq[j] = (tmp[j] - 1ll * qaq[j] * i % ZZQ + ZZQ) % ZZQ;
}
For (i, 1, n + 2) {
For (j, 0, n + 2) tmp[j] = qaq[j];
Rof (j, n + 1, 0) rps[j] = tmp[j + 1],
tmp[j] = (tmp[j] + 1ll * tmp[j + 1] * i % ZZQ) % ZZQ;
int sp = 1;
For (j, 1, i - 1) sp = 1ll * sp * inv[j] % ZZQ;
For (j, 1, n - i + 2)
sp = 1ll * sp * (ZZQ - inv[j]) % ZZQ;
For (j, 0, n + 1)
com[n][j] = (com[n][j] + 1ll * y[i] *
rps[j] % ZZQ * sp % ZZQ) % ZZQ;
}
}
void init() {
int i, j; inv[1] = 1;
For (i, 2, 101) inv[i] = 1ll * (ZZQ - ZZQ / i) * inv[ZZQ % i] % ZZQ;
For (i, 0, 102) {
pwe[i][0] = 1;
For (j, 1, 100) pwe[i][j] = 1ll * pwe[i][j - 1] * i % ZZQ;
}
For (i, 0, 100) lagrange(i);
For (i, 0, 100) C[i][0] = 1;
For (i, 1, 100) For (j, 1, i)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % ZZQ;
}
int getval(int n, int k) {
int i, x = 1, res = 0;
For (i, 0, k + 1) res = (res + 1ll * com[k][i] * x % ZZQ) % ZZQ,
x = 1ll * x * n % ZZQ;
return res;
}
int main() {
int i, j, k, dalao;
init();
dalao = n = read(); m = read(); K = read();
For (i, 1, m) U[i] = read();
For (i, 1, m) R[i] = read();
For (i, 1, m) dalao = min(dalao, n - R[i]);
For (j, 1, m) For (k, 0, R[j] - 1) {
int miu = k & 1 ? ZZQ - 1 : 1, delta;
delta = 1ll * C[R[j] - 1][k] *
qpow(U[j], R[j] - 1 - k) % ZZQ
* getval(U[j], n + k - R[j]) % ZZQ;
czk[j] = (czk[j] + 1ll * miu * delta % ZZQ) % ZZQ;
}
For (i, K, dalao) {
int miu = i - K & 1 ? ZZQ - 1 : 1,
delta = 1ll * C[n - 1][i] * C[i][K] % ZZQ, pyz = 1;
For (j, 1, m)
pyz = 1ll * pyz * C[n - 1 - i][n - R[j] - i] % ZZQ,
pyz = 1ll * pyz * czk[j] % ZZQ;
ans = (ans + 1ll * miu * delta % ZZQ * pyz % ZZQ) % ZZQ;
}
cout << ans << endl;
return 0;
}