题目大意: 有 n n n 个人(包括B神),有 m m m 门科目,第 i i i 门科目最高分为 U i U_i Ui,给出B神每门科目的分数排名,以及有 k k k 个人被B神碾压(即所有科目分数 ≤ \leq ≤ B神的),问有多少种分数方案?
题解
考虑先确定每个人的每门科目排名在B神前面还是后面,然后再确定具体分数。
由于碾压了 k k k 个人,则剩下的 n − k − 1 n-k-1 n−k−1 个每个至少有 1 1 1 科比他高。令 F i , j F_{i,j} Fi,j 表示这 n − k − 1 n-k-1 n−k−1 个人中,至多有 i i i 个人在第 j j j 门科目排名超过B神,则有 F i , j = ( i R j − 1 ) F_{i,j}=\binom i {R_j-1} Fi,j=(Rj−1i)。
容斥一下,得到 ( n − 1 k ) ∑ i = 0 n − k − 1 ( − 1 ) n − k − 1 − i ( n − k − 1 i ) ∏ j = 1 m F i , j \binom {n-1} k\sum_{i=0}^{n-k-1} (-1)^{n-k-1-i} \binom {n-k-1} i\prod_{j=1}^mF_{i,j} (kn−1)∑i=0n−k−1(−1)n−k−1−i(in−k−1)∏j=1mFi,j,前面的 ( n − 1 k ) \binom {n-1} k (kn−1) 是选出被碾压的 k k k 个人。
然后是确定每科的分数,考虑枚举B神的分数:
∏ i = 1 m ( ∑ j = 1 U i j n − R i ( U i − j ) R i − 1 ) = ∏ i = 1 m ( ∑ j = 1 U i j n − R i ∑ k = 0 R i − 1 ( R i − 1 k ) ( − 1 ) k j k U i R i − 1 − k ) = ∏ i = 1 m ( ∑ k = 0 R i − 1 ( − 1 ) k ( R i − 1 k ) U i R i − 1 − k ∑ j = 1 U i j n − R i j k ) = ∏ i = 1 m ( ∑ k = 0 R i − 1 ( − 1 ) k ( R i − 1 k ) U i R i − 1 − k ∑ j = 1 U i j n − R i + k ) \begin{aligned} &\prod_{i=1}^m\left(\sum_{j=1}^{U_i} j^{n-R_i}(U_i-j)^{R_i-1}\right)\\ &=\prod_{i=1}^m\left(\sum_{j=1}^{U_i} j^{n-R_i}\sum_{k=0}^{R_i-1}\binom {R_i-1} k (-1)^kj^kU_i^{R_i-1-k}\right)\\ &=\prod_{i=1}^m\left(\sum_{k=0}^{R_i-1} (-1)^k \binom {R_i-1} k U_i^{R_i-1-k} \sum_{j=1}^{U_i} j^{n-R_i}j^k\right)\\ &=\prod_{i=1}^m\left(\sum_{k=0}^{R_i-1} (-1)^k \binom {R_i-1} k U_i^{R_i-1-k} \sum_{j=1}^{U_i} j^{n-R_i+k}\right)\\ \end{aligned} i=1∏m(j=1∑Uijn−Ri(Ui−j)Ri−1)=i=1∏m(j=1∑Uijn−Rik=0∑Ri−1(kRi−1)(−1)kjkUiRi−1−k)=i=1∏m(k=0∑Ri−1(−1)k(kRi−1)UiRi−1−kj=1∑Uijn−Rijk)=i=1∏m(k=0∑Ri−1(−1)k(kRi−1)UiRi−1−kj=1∑Uijn−Ri+k)
后面是个自然数幂求和,套个拉格朗日插值就行了。最后把上下两部分乘起来就是答案。时间复杂度 O ( n 2 m ) O(n^2m) O(n2m)。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 310
#define mod 1000000007
int n,m,k,U[maxn],R[maxn];
int fac[maxn],inv[maxn],inv_fac[maxn];
void FacInit(){
fac[0]=inv_fac[0]=inv[1]=1;
for(int i=1;i<=maxn-10;i++)fac[i]=1ll*fac[i-1]*i%mod;
for(int i=2;i<=maxn-10;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=maxn-10;i++)inv_fac[i]=1ll*inv_fac[i-1]*inv[i]%mod;
}
int Binom(int x,int y){
if(x<y||y<0)return 0;
return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;
}
int ans1=0,ans2=1;
void add(int &x,int y){
x=(x+y>=mod?x+y-mod:x+y);}
void dec(int &x,int y){
x=(x-y<0?x-y+mod:x-y);}
void solve1(){
for(int i=0;i<=n-k-1;i++){
int prod=Binom(n-k-1,i);
for(int j=1;j<=m;j++)
prod=1ll*prod*Binom(i,R[j]-1)%mod;
(n-k-1-i&1?dec:add)(ans1,prod);
}
ans1=1ll*ans1*Binom(n-1,k)%mod;
}
int ksm(int x,int y){
int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
struct Lagrange{
Lagrange(){
}
int pre[maxn],suf[maxn];
int calc(int x,int k){
if(x<=k+2){
int re=0;
for(int i=1;i<=x;i++)
add(re,ksm(i,k));
return re;
}else{
int re=0,sum=0;
pre[0]=1;for(int i=1;i<=k+2;i++)pre[i]=1ll*pre[i-1]*(x-i)%mod;
suf[k+3]=1;for(int i=k+2;i>=1;i--)suf[i]=1ll*suf[i+1]*(x-i)%mod;
for(int i=1;i<=k+2;i++){
add(sum,ksm(i,k));
(k+2-i&1?dec:add)(re,1ll*sum*pre[i-1]%mod*suf[i+1]%mod*inv_fac[i-1]%mod*inv_fac[k+2-i]%mod);
}
return re;
}
}
}Lag;
void solve2(){
for(int i=1;i<=m;i++){
int tot=0;
for(int p=0;p<=R[i]-1;p++)
(p&1?dec:add)(tot,1ll*Binom(R[i]-1,p)*ksm(U[i],R[i]-1-p)%mod*Lag.calc(U[i],n-R[i]+p)%mod);
ans2=1ll*ans2*tot%mod;
}
}
int main()
{
scanf("%d %d %d",&n,&m,&k);FacInit();
for(int i=1;i<=m;i++)scanf("%d",&U[i]);
for(int i=1;i<=m;i++)scanf("%d",&R[i]);
solve1();solve2();printf("%lld",1ll*ans1*ans2%mod);
}