【BZOJ4559】[JLoi2016]成績比較 動態規劃+容斥+組合數學
【BZOJ4559】[JLoi2016]成績比較
Description
G系共有n位同學,M門必修課。這N位同學的編號為0到N-1的整數,其中B神的編號為0號。這M門必修課編號為0到M-1的整數。一位同學在必修課上可以獲得的分數是1到Ui中的一個整數。如果在每門課上A獲得的成績均小於等於B獲得的成績,則稱A被B碾壓。在B神的說法中,G系共有K位同學被他碾壓(不包括他自己),而其他N-K-1位同學則沒有被他碾壓。D神查到了B神每門必修課的排名。這裏的排名是指:如果B神某門課的排名為R,則表示有且僅有R-1位同學這門課的分數大於B神的分數,有且僅有N-R位同學這門課的分數小於等於B神(不包括他自己)。我們需要求出全系所有同學每門必修課得分的情況數,使其既能滿足B神的說法,也能符合D神查到的排名。這裏兩種情況不同當且僅當有任意一位同學在任意一門課上獲得的分數不同。你不需要像D神那麽厲害,你只需要計算出情況數模10^9+7的余數就可以了。Input
Output
僅一行一個正整數,表示滿足條件的情況數模10^9+7的余數。
Sample Input
3 2 12 2
1 2
Sample Output
10題解:本題可以分為兩部分處理,答案等於兩部分的方案數之積。
第一部分是在碾壓K個人的前提下,所有人每門課的分數與B神分數的大小關系的方案數。不難想到容斥,用f[i]表示至少碾壓了i個人的方案數,那麽$f[i]=C_{n-1}^i\prod\limits_{j=1}^mC_{n-i-1}^{Rj-1}$。答案=至少碾壓K個人-至少碾壓K+1個人+至少碾壓K+2個人。。。所以$ans1=\sum\limits_{i=K}^n(-1)^{K-i}C_i^kf[i]$。
第二部分是在已經確定所有人每門課與B神的相對關系的情況下,每個人得分的方案數。我們可以先分別計算每門課的方案數,最後將其乘起來。設當前課B神的排名為R,總分為U。一個比較暴力的方法就是我們枚舉B神的得分x,那麽方案數就是$x^{n-R}(U-x)^{R-1}$。所以這門課的總方案數就是:
$\sum\limits_{x=1}^Ux^{n-R}(U-x)^{R-1}\\=\sum\limits_{x=1}^U\sum\limits_{k=0}^{R-1}(-1)^kx^{n-1-k}U^k\\=\sum\limits_{k=0}^{R-1}(-1)^kU^k\sum\limits_{x=1}^Ux^{n-1-k}$
所以現在問題就在於如何快速求$\sum\limits_{i=1}^si^k$,我們設這個東西=g[k]。下面這步非常神:我們觀察這個式子
$(s+1)^k-s^k=\sum\limits_{j=0}^{k-1}C_k^js^j\\s^k-(s-1)^k=\sum\limits_{j=0}^{k-1}C_k^j(s-1)^j\\...\\2^k-1^k=\sum\limits_{j=0}^{k-1}C_k^j1^j$
等式兩邊分別求和
$\sum\limits_{i=1}^s(i+1)^k-i^k=\sum\limits_{i=1}^{s}\sum\limits_{j=0}^{k-1}C_k^ji^j\\(s+1)^k-1=\sum\limits_{j=0}^{k-1}C_k^j\sum\limits_{i=1}^si^j=\sum\limits_{j=0}^{k-1}C_k^jg[j]$
將g[k-1]放到左面即可得
$g[k-1]=\frac {(s+1)^k-1-\sum\limits_{j=0}^{k-2}C_k^jg[j]} {C_k^{k-1}}$
遞推求出g[k]即可。
時間復雜度$O(n^3)$。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const ll P=1000000007; int n,m,K; ll ans1,ans2; int R[110]; ll c[110][110],f[110],U[110],g[110]; inline ll pm(ll x,ll y) { ll z=1; while(y) { if(y&1) z=z*x%P; x=x*x%P,y>>=1; } return z; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(),K=rd(),ans2=1; int i,j,k; for(i=0;i<=max(n,m);i++) { c[i][0]=1; for(j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%P; } for(i=1;i<=m;i++) U[i]=rd(); for(i=1;i<=m;i++) R[i]=rd(); for(i=n-1;i>=K;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]%P; ans1=(ans1+(((i^K)&1)?-1:1)*f[i]*c[i][K]%P+P)%P; } for(i=1;i<=m;i++) { ll tmp=0; g[0]=U[i]; for(k=1;k<=n;k++) { g[k]=(pm(U[i]+1,k+1)-1+P)%P; for(j=0;j<k;j++) g[k]=(g[k]-c[k+1][j]*g[j]%P+P)%P; g[k]=g[k]*pm(c[k+1][k],P-2)%P; } for(j=0;j<=R[i]-1;j++) tmp=(tmp+((j&1)?-1:1)*c[R[i]-1][j]*pm(U[i],R[i]-j-1)%P*g[n-R[i]+j]%P+P)%P; ans2=ans2*tmp%P; } printf("%lld",ans1*ans2%P); return 0; }
【BZOJ4559】[JLoi2016]成績比較 動態規劃+容斥+組合數學