首先考虑可以分成两个部分计算,即人数和分数.
1. 人数的计算:
很明显可以容斥,设\(f_{i}\)表示至少吊打\(i\)个人,那么有:
此时容斥系数不为\(\pm 1\).
2. 分数的计算:
考虑单独计算一科的分数,为:
前面的直接枚举,后面的自然数幂和用第二类斯特林数算即可.
#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\n",ans);
return 0;
}
原文:https://www.cnblogs.com/fexuile/p/12868858.html