「JLOI / SHOI2016」成绩比较
传送门
题解
首先考虑可以分成两个部分计算,即人数和分数.
1. 人数的计算:
很明显可以容斥,设(f_{i})表示至少吊打(i)个人,那么有:
[egin{align}
f_{i}&=inom{n-1}{i}prod_{j=1}^minom{r_j-1}{n-i-1}
\
ans&=sum_{i=k}^nf_iinom{i}{k}-1^{i-k}
end{align}
]
此时容斥系数不为(pm 1).
2. 分数的计算:
考虑单独计算一科的分数,为:
[egin{align}
ans_i&=sum_{j=1}^{u_i}j^{n-r_i}{(u_i-j)}^{r_i-1}
\
&=sum_{j=1}^{u_i}j^{n-r_i}sum_{k=0}^{r_i-1}-1^ku_i^{r_i-1-k}j^{k}inom{r_i-1}{k}
\
&=sum_{j=1}^{u_i}sum_{k=0}^{r_i-1}-1^ku_i^{r_i-1-k}j^{n-r_i+k}inom{r_i-1}{k}
\
&=sum_{k=0}^{r_i-1}-1^kinom{r_i-1}{k}u_i^{r_i-1-k}sum_{j=1}^{u_i}j^{n-r_i+k}
end{align}
]
前面的直接枚举,后面的自然数幂和用第二类斯特林数算即可.
[sum_{i=1}^ni^k=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}frac{(n+1)^{underline {j+1}}}{j+1}
]
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=210,Mod=1e9+7;
int n,m,k,u[N],r[N];
int c[N][N],S[N][N];
int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
int calc(int n,int k)
{
int down=1,ret=0;
for(int j=0;j<=k;j++)
{
down=1ll*down*(n+1-j)%Mod;
ret=(ret+1ll*down*S[k][j]%Mod*qpow(j+1,Mod-2)%Mod)%Mod;
}
return ret;
}
int main()
{
n=gi();m=gi();k=gi();
c[0][0]=1;
for(int i=1;i<=200;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
}
S[0][0]=1;
for(int i=1;i<=200;i++)
{
for(int j=1;j<=200;j++)
S[i][j]=(S[i-1][j-1]+1ll*j*S[i-1][j]%Mod)%Mod;
}
for(int i=1;i<=m;i++)u[i]=gi();
for(int i=1;i<=m;i++)r[i]=gi();
int ans=0;
for(int i=0,f=(n-k-1)&1?Mod-1:1;i<=n-k-1;i++,f=Mod-f)
{
int res=1ll*f*c[n-k-1][i]%Mod;
for(int j=1;j<=m;j++)res=1ll*res*c[i][r[j]-1]%Mod;
ans=(ans+res)%Mod;
}
ans=1ll*ans*c[n-1][k]%Mod;
for(int i=1;i<=m;i++)
{
int res=0;
for(int p=0,f=(r[i]-1)&1?Mod-1:1;p<r[i];p++,f=Mod-f)
res=(res+1ll*f*c[r[i]-1][p]%Mod*qpow(u[i],p)%Mod*calc(u[i],n-p-1)%Mod)%Mod;
ans=1ll*ans*res%Mod;
}
printf("%d
",ans);
return 0;
}