把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3270 [JLOI2016]成绩比较

题面传送门
我们发现我们并不能求出恰好被碾压的人数,但是我们可以求出至少有\(k\)个被碾压的人数。
具体的,先钦定\(k\)个人一定被碾压,然后剩下的乱选,我们就可以得到答案了。
发现这个计算过程需要枚举B的分数,然后计算,发现这个是一个\(n\)次多项式,那么拉格朗日插值就好了。
时间复杂度\(O(n^3)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 100
#define M 30
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-4)
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
using namespace std;
int n,m,k,U[N+5],R[N+5],Minn=1e9;ll Ans,F[N+5],C[N+5][N+5],W[N+5],G[N+5];
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
I ll calc(int x,int U){
	ll Ans=0;for(RI i=1;i<=U;i++) Ans+=mpow(i,n-R[x])%mod*mpow(U-i,R[x]-1)%mod;return Ans%mod;
}
I ll LGLR(int x){
	RI i,j;for(i=1;i<=n+1;i++) G[i]=calc(x,i);ll ToT=0,F1,F2;
	for(i=1;i<=n+1;i++) {
		for(F1=F2=1,j=1;j<=n+1;j++) i^j&&(F1=F1*(U[x]-j)%mod,F2=F2*(i-j)%mod);ToT+=F1*mpow(F2)%mod*G[i]%mod;
	}return (ToT%mod+mod)%mod;
}
int main(){
//	freopen("1.in","r",stdin);
	RI i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<=m;i++) scanf("%d",&U[i]);for(i=1;i<=m;i++) scanf("%d",&R[i]),Minn=min(Minn,n-R[i]);
	for(C[0][0]=i=1;i<=n;i++){
		for(C[i][0]=j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
	for(i=1;i<=m;i++){
		if(U[i]<=n){W[i]=calc(i,U[i]);continue;}
		W[i]=LGLR(i);
	}
	for(i=Minn;i;i--){
		F[i]=C[n-1][i];for(j=1;j<=m;j++) F[i]=F[i]*C[n-i-1][(n-R[j])-i]%mod/**mpow(C[n-R[j]][i])%mod*/*W[j]%mod/*,printf("%d\n",R[j]-i)*/;
	}
	for(i=k;i<=n;i++) Ans+=((i-k)&1?mod-C[i][k]:C[i][k])*F[i]%mod;printf("%lld\n",Ans%mod);
}
posted @ 2021-10-20 17:55  275307894a  阅读(23)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end