[JLoi2016]成绩比较
题解:
一道不错的题目
好像有容斥的方法。。我没看不知道
首先dp是比较简单的
f[i][j]表示考虑了前m门课,完全碾压了j个人
那么转移是
f[i][j]=sigma { f[i-1][k]*C(j,k)*C(n-j,a[i]-k) } *pi
时间复杂度n^3
其中pi表示选出他们分数的方案数
我们显然可以通过枚举我的得分来确定pi
pi=sigma {(maxn-x)^(rank[i]-1)*x^(n-rank[i])}
再下面就是看了别人题解才知道得。。
首先maxn非常大,所以暴力算一定是不可以的
上面的式子看上去比较复杂
将它写作 sigma{x,(k-x)^a*x^b}
将(k-x)^a用二项式定理展开
得到 C()*x^a*x^b+C()*k*x^a-1*x*b+.....
将每项拆开
得到C()*k^...*sigma{x,x^(a+b)}+......+......
现在的问题就在于维护自然数幂和了
由于模数是1e9+7
选择拉格朗日插值就可以了
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define IL inline #define rint register int #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T>IL void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } const int N=3e2+10; const int mo=1e9+7; const int INF=1e9; int a[N],b[N],r[N],C[205][205],dp[N][N],f[N],jc[N]; int n,m,k; IL void js(int &x,int y) { x+=y; if (x>mo) x-=mo; } int qpow(int x,int y) { if (y==0) return(1); if (y==1) return(x); int kk=qpow(x,y/2); kk=(1ll*kk*kk)%mo; if (y%2) kk=(1ll*kk*x)%mo; return(kk); } int query(int x,int k) { rep(i,1,k+2) f[i]=(f[i-1]+qpow(i,k))%mo; if (x<=k+2) return(f[x]); jc[0]=1; rep(i,1,k+2) jc[i]=(1ll*jc[i-1]*i)%mo; int now=1,ans=0; rep(i,1,k+2) now=1ll*now*(x-i)%mo; rep(i,1,k+2) { int inv1=qpow(x-i,mo-2); int inv2=qpow(1ll*jc[i-1]*jc[k+2-i]%mo,mo-2); if ((k+2-i)%2) inv2=-inv2+mo; js(ans,1ll*inv1*inv2%mo*now%mo*f[i]%mo); } return(ans); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); read(k); rep(i,1,m) read(a[i]); rep(i,1,m) read(r[i]),b[i]=n-r[i]; rep(i,0,200) C[i][0]=1; rep(i,1,200) rep(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo; dp[1][b[1]]=C[n-1][b[1]]; rep(i,2,m) rep(j,k,b[i]) { int tmp=0; rep(kk,j,n-1) { int tmp1=dp[i-1][kk]; js(tmp,1ll*tmp1*C[kk][j]%mo*C[n-kk-1][b[i]-j]%mo); } dp[i][j]=tmp; } int ans=dp[m][k]; rep(i,1,m) { rint kk=0; rep(j,0,r[i]-1) { int kk1=1ll*C[r[i]-1][j]*query(a[i],j+n-r[i])%mo*qpow(a[i],r[i]-1-j)%mo; if (j%2) kk1=-kk1+mo; js(kk,kk1); } ans=(1ll*ans*kk)%mo; } cout<<(ans+mo)%mo<<endl; return 0; }