[luogu P3270] [JLOI2016]成绩比较

先不考虑分数
首先设 N = n − k − 1 N = n - k - 1 N=nk1,表示B神没能碾压的人
这个显然是 C n − 1 N C_{n-1}^{N} Cn1N

对于第 i i i科,排在B神前面的肯定在N里面
C N r a n k [ i ] − 1 \large C_{N}^{rank[i]-1} CNrank[i]1

m m m个科目的答案乘起来
F ( m ) = ∏ i = 1 m C N r a n k [ i ] − 1 \large F(m)=\prod\limits_{i=1}^{m} C_{N}^{rank[i]-1} F(m)=i=1mCNrank[i]1
显然这个会把一些不合法的算进去
怎么办?
容斥就好了
a n s = ∑ i = 0 N ( − 1 ) N − i   C N i F ( i ) \large ans=\sum\limits_{i=0}^{N} (-1)^{N-i} \ C_{N}^{i}F(i) ans=i=0N(1)Ni CNiF(i)
a n s = ∑ i = 0 N ( − 1 ) N − i   C N i ∏ j = 1 m C i r a n k [ j ] − 1 \large ans=\sum\limits_{i=0}^{N} (-1)^{N-i} \ C_{N}^{i}\prod\limits_{j=1}^{m} C_{i}^{rank[j]-1} ans=i=0N(1)Ni CNij=1mCirank[j]1
这个计算是 O ( n m ) O(nm) O(nm)
加上分数怎么搞呢?
枚举B神的分数
S i = ∑ x = 1 U i x n − r a n k [ i ] ( U i − x ) r a n k [ i ] − 1 \large S_i=\sum\limits_{x=1}^{U_i}x^{n-rank[i]}(U_i-x)^{rank[i]-1} Si=x=1Uixnrank[i](Uix)rank[i]1
二项式展开
( U i − x ) r a n k [ i ] − 1 = ∑ t = 0 r a n k [ i ] − 1 ( − 1 ) t C r a n k [ i ] − 1 t x t U i r a n k [ i ] − 1 − t (U_i-x)^{rank[i]-1}=\sum\limits_{t=0}^{rank[i]-1} (-1)^tC_{rank[i]-1}^{t}x^tU_i^{rank[i]-1-t} (Uix)rank[i]1=t=0rank[i]1(1)tCrank[i]1txtUirank[i]1t

( U i − x ) r a n k [ i ] − 1 = ∑ t = 0 r a n k [ i ] − 1 ( − 1 ) t x t U i r a n k [ i ] − 1 − t C r a n k [ i ] − 1 t (U_i-x)^{rank[i]-1}=\sum\limits_{t=0}^{rank[i]-1} (-1)^tx^tU_i^{rank[i]-1-t}C_{rank[i]-1}^{t} (Uix)rank[i]1=t=0rank[i]1(1)txtUirank[i]1tCrank[i]1t

S i = ∑ x = 1 U i x n − r a n k [ i ] ∑ t = 0 r a n k [ i ] − 1 ( − 1 ) t x t U i r a n k [ i ] − 1 − t C r a n k [ i ] − 1 t \large S_i=\sum\limits_{x=1}^{U_i}x^{n-rank[i]}\sum\limits_{t=0}^{rank[i]-1} (-1)^tx^tU_i^{rank[i]-1-t}C_{rank[i]-1}^{t} Si=x=1Uixnrank[i]t=0rank[i]1(1)txtUirank[i]1tCrank[i]1t
S i = ∑ x = 1 U i ∑ t = 0 r a n k [ i ] − 1 ( − 1 ) t x n − r a n k [ i ] + t U i r a n k [ i ] − 1 − t C r a n k [ i ] − 1 t \large S_i=\sum\limits_{x=1}^{U_i}\sum\limits_{t=0}^{rank[i]-1} (-1)^tx^{n-rank[i]+t}U_i^{rank[i]-1-t}C_{rank[i]-1}^{t} Si=x=1Uit=0rank[i]1(1)txnrank[i]+tUirank[i]1tCrank[i]1t
交换求和顺序
S i = ∑ t = 0 r a n k [ i ] − 1 ( − 1 ) t U i r a n k [ i ] − 1 − t C r a n k [ i ] − 1 t ∑ x = 1 U i x n − r a n k [ i ] + t \large S_i=\sum\limits_{t=0}^{rank[i]-1} (-1)^tU_i^{rank[i]-1-t}C_{rank[i]-1}^{t}\sum\limits_{x=1}^{U_i}x^{n-rank[i]+t} Si=t=0rank[i]1(1)tUirank[i]1tCrank[i]1tx=1Uixnrank[i]+t

A N S = C n − 1 N ∗ a n s ∗ ∏ i = 1 m S i \large ANS = C_{n-1}^{N}*ans*\prod\limits_{i=1}^{m}S_i ANS=Cn1Nansi=1mSi
然后就可以了
∏ i = 1 m S i \prod\limits_{i=1}^{m}S_i i=1mSi计算这个东西是 O ( m n 2 ) O(mn^2) O(mn2)的,这就是上限


让我们来看看展开后的毒瘤式子吧
A N S = C n − 1 N ∗ ∑ i = 0 N ( − 1 ) N − i   C N i ∏ j = 1 m C i r a n k [ j ] − 1 ∗ ∏ k = 1 m ∑ t = 0 r a n k [ k ] − 1 ( − 1 ) t U k r a n k [ k ] − 1 − t C r a n k [ k ] − 1 t ∑ x = 1 U k x n − r a n k [ k ] + t ANS = C_{n-1}^{N}*\sum\limits_{i=0}^{N} (-1)^{N-i} \ C_{N}^{i}\prod\limits_{j=1}^{m} C_{i}^{rank[j]-1}*\prod\limits_{k=1}^{m}\sum\limits_{t=0}^{rank[k]-1} (-1)^tU_k^{rank[k]-1-t}C_{rank[k]-1}^{t}\sum\limits_{x=1}^{U_k}x^{n-rank[k]+t} ANS=Cn1Ni=0N(1)Ni CNij=1mCirank[j]1k=1mt=0rank[k]1(1)tUkrank[k]1tCrank[k]1tx=1Ukxnrank[k]+t

还是看这条吧
A N S = C n − 1 N ∗ a n s ∗ ∏ i = 1 m S i \large ANS = C_{n-1}^{N}*ans*\prod\limits_{i=1}^{m}S_i ANS=Cn1Nansi=1mSi
直接rush就好了
忘记讲了
∑ x = 1 U i x n − r a n k [ i ] + t \sum\limits_{x=1}^{U_i}x^{n-rank[i]+t} x=1Uixnrank[i]+t这个是多项式幂和,可以用拉格朗日插值法 O ( n ) O(n) O(n)求出

code:

#include<bits/stdc++.h>
#define N 1000005
#define int long long
#define mod 1000000007
using namespace std;
int qpow(int x, int y) {
	int ret = 1;
	for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
	return ret;
}
int Fac[N], iFac[N], S[N], U[N], R[N];
int C(int x, int y) {
	if(x < y) return 0;
	return Fac[x] * iFac[y] % mod * iFac[x - y] % mod;
}
int n, m, k, x[N], y[N], fac[N], pre[N], suf[N];
int nk(int n, int k) {
	swap(n, k);
	n += 2;
	for(int i = 1; i <= n; i ++) {
		x[i] = i;
		y[i] = (y[i - 1] + qpow(i, n - 2)) % mod;
	}
	fac[0] = pre[0] = suf[n + 1] = 1;
	int s = 1;
	for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod, pre[i] = pre[i - 1] * (k - x[i] + mod)% mod;
	for(int i = n; i >= 1; i --) suf[i] = suf[i + 1] * (k - x[i] + mod) % mod;
	int ans = 0;
	for(int i = 1; i <= n; i ++) {
		int pi = pre[x[i] - 1] * suf[x[i] + 1] % mod;
		int ha = fac[x[i] - 1] * fac[n - x[i]] % mod; 
		if((n - i) & 1) ha = (mod - ha) % mod;
		pi = pi * qpow(ha, mod - 2) % mod;
		ans = (ans + y[i] * pi % mod) % mod;
	}
	return ans;
}

signed main() {
	scanf("%lld%lld%lld", &n, &m, &k);
	int nn = n - k - 1;
	for(int i = 1; i <= m; i ++) scanf("%lld", &U[i]);
	for(int i = 1; i <= m; i ++) scanf("%lld", &R[i]);
	
	Fac[0] = 1;
	for(int i = 1; i <= n; i ++) Fac[i] = Fac[i - 1] * i % mod;
	iFac[n] = qpow(Fac[n], mod - 2);
	for(int i = n - 1; i >= 0; i --) iFac[i] = iFac[i + 1] * (i + 1) % mod;
	
	int ANS = C(n - 1, nn);
	int ans = 0;
	for(int i = 0; i <= nn; i ++) {
		int ret = 1;
		for(int j = 1; j <= m; j ++) ret = ret * C(i, R[j] - 1) % mod;
		
		ret = ret * C(nn, i) % mod;
		if((nn - i) & 1) ans = (ans - ret + mod) % mod;
		else ans = (ans + ret) % mod; 
	}
	for(int i = 1; i <= m; i ++) {
		for(int t = 0; t <= R[i] - 1; t ++) {
			int ret = qpow(U[i], R[i] - 1 - t);
			ret = ret * C(R[i] - 1, t) % mod;
			ret = ret * nk(U[i], n - R[i] + t) % mod;
			if(t & 1) S[i] = (S[i] - ret + mod) % mod;
			else S[i] = (S[i] + ret) % mod;			
		}
	}
	ANS = ANS * ans % mod;
	for(int i = 1; i <= m; i ++) ANS = ANS * S[i] % mod;
	printf("%lld", ANS);
	return 0;
}

这条式子我推了半个小时
哈哈哈哈哈哈我没疯,放开我哈哈哈,哈那塞哈哈哈哈

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页