BZOJ 4559 成绩比较
作者:互联网
题意:https://www.lydsy.com/JudgeOnline/problem.php?id=4559
Sol:
第一眼看起来就是个稍微麻烦的组合数
但是发现如果钦点哪些同学分数在某科目上分数比B神低以后的方案,就会出现没有被钦
点碾压的同学也会被碾压,(后面钦点分数时可能钦点的一直是同一批人导致人数不够不被碾压的人数)
于是可以考虑容斥,用至少i个人的方案算出恰好k个人的方案。
可以得到
因为被碾压的不能超过B君最大的一个排名,所以定义up=min{n−Ri}
i=k∑up(−1)i−kCikCn−1ij=1∏mCn−i−1Rj−1x=1∑Uj(Uj−x)Rj−1xn−Rj
发现后边枚举分数的∑实际上是在对关于Uj的多项式做前缀和,因此是个n次多项式,拉格朗日插值即可。
#include<cctype>
#include<cmath>
#include<cstdio>
const int N = 1e2+9;
typedef long long LL;
const int upmax = 1e2+5;
#define p 1000000007
#define debug printf("GG\n")
inline int min(int a, int b) {return a > b ? b : a;}
inline LL FST(LL b, LL k) {
if (!b && k > 0) return 0;
LL ans = 1LL;
while (k) {
if (k & 1) ans = ans * b % p; b = b * b % p, k >>= 1;
} return ans;
}
int n, m, k, rk[N]; LL U[N];
LL lagr(LL *ax, LL *ay, int up, LL x) {
LL res = 0;
for (int i = 1; i <= up; i++) {
LL s1 = 1, s2 = 1;
for (int j = 1; j <= up; j++) {
if (i == j) continue;
s1 = (LL)(s1 * ((x - ax[j]) % p + p) % p) % p;
s2 = (LL)(s2 * ((ax[i] - ax[j]) % p + p)) % p;
} res = (res + (LL)(s1 * FST(s2, p - 2)) % p * ay[i] % p) % p;
} return res;
} LL tx[N], ty[N], poly[N]; LL inv[N], fac[N];
inline LL C(int n, int m) {
return fac[n] * inv[n - m] % p * inv[m] % p;
}int up;
void init() {
scanf("%d%d%d", &n, &m, &k);
inv[1] = 1LL, fac[1] = 1LL, fac[0] = inv[0] = 1LL;
for (int i = 2; i <= upmax; i++) inv[i] = inv[i - 1] * FST(i, p - 2) % p;
for (int i = 2; i <= upmax; i++) fac[i] = fac[i - 1] * (LL)i % p;
for (int i = 1; i <= m; i++) scanf("%lld", &U[i]);
for (int i = 1; i <= m; i++) scanf("%d", &rk[i]);
for (int i = 1; i <= m; i++) {
int R = rk[i];
for (int j = 1; j <= n + 1; j++) {
tx[j] = j, ty[j] = 0;
for (int x = 1; x <= j; x++)
ty[j] = (ty[j] + FST(j - x, R - 1) * FST(x, n - R) % p) % p;
} poly[i] = lagr(tx, ty, n + 1, U[i]);
}
up = n;
for (int i = 1; i <= m; i++) up = min(up, n - rk[i]);
}
void solve() {
LL ans = 0;
for (int i = k; i <= up; i++) {
LL res = ((i - k) & 1 ? -1 : 1) * C(i, k) % p * C(n - 1, i) % p;
for (int j = 1; j <= m; j++)
res = res * poly[j] % p * C(n - i - 1, rk[j] - 1) % p;
ans = (ans + res) % p;
} printf ("%lld\n", (ans % p + p) % p);
}
void debugR() {
LL ans = 0;
for (int i = k; i <= up; i++) {
LL res = ((i - k) & 1 ? -1 : 1) * C(n - 1, i) % p * C(i, k) % p;
res = (res % p + p) % p;
for (int j = 1; j <= m; j++) {
LL res2 = 0;
for (int og = 1; og <= U[j]; og++) {
res2 = (res2 + FST(U[j] - og, rk[j] - 1) * FST(og, n - rk[j]) % p) % p;
}
res = res2 * res % p * C(n - 1 - i, n - rk[j] - i) % p;
} ans = (ans + res) % p;
} printf("%lld\n",(ans % p + p) % p);
}
int main() {
init(), solve();
// debugR();
}
标签:min,int,LL,ans,up,4559,成绩,Rj,BZOJ 来源: https://blog.csdn.net/qq_42880894/article/details/90339084