[JLOI2016] 成绩比较 题解
考虑大力推式子。容易想到对被碾压的人容斥,则有:
\[\begin{aligned}
ans&=\sum_{i=k}^{N-1}(-1)^{i-k}\binom{i}{k}\binom{N-1}{i}\prod_{j=0}^{M-1}\sum_{l=1}^{U_j}l^{N-R_j}(U_j-l)^{R_j-1}\binom{N-i-1}{N-i-R_j}\\
&=\sum_{i=k}^{N-1}(-1)^{i-k}\frac{(N-i)!}{i!}((N-i-1)!)^{M-1}\prod_{j=0}^{M-1}\frac 1{(N-i-R_j)!(R_j-1)!}\sum_{l=1}^{U_j}l^{N-R_j}(U_j-l)^{R_j-1}\\
&=(\sum_{l=1}^{U_j}l^{N-R_j}(U_j-l)^{R_j-1})\times
(\sum_{i=k}^{N-1}(-1)^{i-k}\frac{(N-i)!}{i!}((N-i-1)!)^{M-1}\prod_{j=0}^{M-1}\frac 1{(N-i-R_j)!(R_j-1)!})
\end{aligned}\]
后半部分暴力枚举,前半部分是一个 \(n\) 次多项式,拉格朗日插值即可。
时间复杂度 \(O(n^2m)\),可以用一些手法优化到 \(O(nm+n^2)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=105,p=1e9+7;
int qpow(int x,int y){
	int re=1;
	while(y){
		if(y&1) re=re*x%p;
		x=x*x%p,y>>=1;
	}return re;
}int n,m,k,ans,u[N],rk[N],jc[N],inv[N],mn=1e9;
int as(int u,int x,int y){
	int re=0;
	for(int i=1,yc=0;i<=n+1;i++){
		yc=(yc+qpow(i,x)*qpow(u-i,y))%p;int nw=yc;
		for(int j=1;j<=n+1;j++) if(j!=i)
			nw=nw*(u-j+p)%p*qpow(i-j+p,p-2)%p;
		re=(re+nw)%p;
	}return re;
}signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>k,jc[0]=inv[0]=1;
	for(int i=1;i<=m;i++) cin>>u[i];
	for(int i=1;i<=m;i++) cin>>rk[i],mn=min(mn,n-rk[i]);
	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%p;
	inv[n]=qpow(jc[n],p-2);
	for(int i=n-1;i;i--) inv[i]=inv[i+1]*(i+1)%p;
	for(int i=k;i<=mn;i++){
		int sum=jc[n-1]*inv[k]%p*inv[i-k]%p*qpow(jc[n-i-1],m-1)%p;
		for(int j=1;j<=m;j++) sum=sum*inv[n-i-rk[j]]%p*inv[rk[j]-1]%p;
		ans=(ans+((i-k)%2?-1:1)*sum+p)%p;
	}for(int i=1;i<=m;i++)
		ans=ans*as(u[i],n-rk[i],rk[i]-1)%p;
	return cout<<ans,0;
}

                
            
        
浙公网安备 33010602011771号