P3270 [JLOI2016]成绩比较(拉格朗日插值)

传送门

挺神仙的啊……

(f[i][j])为考虑前(i)门课程,有(j)个人被(B)爷碾压的方案数,那么转移为$$f[i][j]=sum_{k=j}^{n-1}f[i-1][k] imes {k choose k-j} imes {n-1-k choose r[i]-1-(k-j)} imes g(i)$$
解释一下,就是考虑第(i)门课,枚举在这之前分比(B)爷高的人数(k),要从中选出(k-j)个使得他们这一门课的分数比(B)爷高,然后在剩下的(n-1-k)个人里选出(r[i]-1-(k-j))个人使他们比(B)爷分数高

最后的(g(i))表示对于第(i)门课程,把(1)(u[i])的分数分给(n-1)个人使得他们中比(B)爷分数高的人数为(r[i])的方案数

可以枚举(B)爷的分数,得$$g[i]=sum_{k=1}^{u_i}k^{n-r[i]}(u_i-k)^{r[i]-1}$$
然而(u_i)太大不好直接算,发现后面那东西是一个多项式,且多项式的次数为(n-1),所以可以用拉格朗日插值快速计算

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=155,P=1e9+7;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
int C[N][N],f[N][N],u[N],r[N],g[N];
int n,m,k;
int Large(int d,int r){
	fp(i,0,n){
		g[i]=0;
		fp(j,1,i)g[i]=add(g[i],1ll*ksm(j,n-r)*ksm(i-j,r-1)%P);
	}if(d<=n)return g[d];
	int res=0,ty=(n&1)?P-1:1,tmp=1;
	fp(i,1,n)tmp=1ll*tmp*(d-i)%P*ksm(i,P-2)%P;
	fp(i,0,n){
		res=add(res,1ll*g[i]*ty%P*tmp%P);
		tmp=1ll*tmp*(d-i)%P*ksm(d-i-1,P-2)%P*(n-i)%P*ksm(i+1,P-2)%P;
		ty=P-ty;
	}return res;
}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read(),m=read(),k=read();
	fp(i,1,m)u[i]=read();
	fp(i,1,m)r[i]=read();
	fp(i,0,N-5){
		C[i][0]=1;
		fp(j,1,i)C[i][j]=add(C[i-1][j],C[i-1][j-1]);
	}
	f[0][n-1]=1;
	fp(i,1,m){
		int res=Large(u[i],r[i]);
		fp(j,k,n-1){
			fp(l,j,n-1)if(l-j<=r[i]-1)
				f[i][j]=add(f[i][j],1ll*f[i-1][l]*C[l][l-j]%P*C[n-1-l][r[i]-1-(l-j)]%P);
			f[i][j]=mul(f[i][j],res);
		}
	}printf("%d
",f[m][k]);return 0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10217322.html