[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
第一行包含三个正整数N,M,K,分别表示G系的同学数量(包括B神),必修课的数量和被B神碾压的同学数量。第二行包含M个正整数,依次表示每门课的最高分Vi。第三行包含M个正整数,依次表示B神在每门课上的排名Ri。保证1≤Ri≤N。数据保证至少有1种情况使得B神说的话成立。N<=100,M<=100,Ui<=10^9

Output
仅一行一个正整数,表示满足条件的情况数模10^9+7的余数。

Sample Input
3 2 1
2 2
1 2

Sample Output
10


思维好题……容斥+组合数

整体思路:先求出所有其他人和B神每门课分数相对大小的不同方案数,然后再计算每门课的方案数,两者乘积即为答案。

①首先算第一部分,直接算不好算,我们考虑容斥原理

\(f[i]\)表示有\(i\)个人被碾压的方案数,那么\(f[i]=\binom{n-1}{i}\times\prod\limits_{j=1}^m\binom{n-i-1}{R_j-1}-\sum\limits_{k=i+1}^{n-1}f[k]\times\binom{k}{i}\),即用至少\(i\)个人被碾压减去非法情况,逆序推导即可

②再算第二部分,对于每个课程单独计算,最后乘起来即可

对于某一门课程\(i\),我们枚举B神的得分,可以得到方案数为

\[\sum\limits_{j=1}^{V_i} j^{n-R_i}\times (V_i-j)^{R_i-1} \]

化简可得

\[\sum\limits_{j=1}^{V_i}\sum\limits_{k=0}^{R_i-1} \binom{R_i-1}{k}\times V_i^k\times (-j)^{n-k-1} \]

调换一下\(\sum\)的顺序可得

\[\sum\limits_{k=0}^{R_i-1} \binom{R_i-1}{k}\times V_i^k\times(-1)^{R_i-k-1}\sum\limits_{j=1}^{V_i}j^{n-k-1} \]

可以发现最后那个\(\sum\)需要\(O(V_i)\)的时间求出,这样显然不行,我们令

\[g[p]=\sum\limits_{i=1}^s i^p \]

然后我们来找一下规律……

\[(s+1)^{p+1}-s^{p+1}=\sum\limits_{i=0}^p\binom{p+1}{i}\times s^i \]

\[s^{p+1}-(s-1)^{p+1}=\sum\limits_{i=0}^p\binom{p+1}{i}\times(s-1)^i \]

\[... \]

\[2^{p+1}-1^{p+1}=\sum\limits_{i=1}^p\binom{p+1}{i}\times1^i \]

将以上式子相加可得

\[(s+1)^{p+1}-1^{p+1}=\sum\limits_{i=0}^p \binom{p+1}{i}\times g[i] \]

\[(1-p)g[p]=1-(s+1)^{p+1}+\sum\limits_{i=0}^{p-1}\binom{p+1}{i}\times g[i] \]

所以我们就可以在\(O(p^2)\)的时间内用正推求出\(g[1...p]\)

这样一来,这题就解决了

/*problem from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1; char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1; char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)	putchar('-');
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e2,p=1e9+7;
int C[N+10][N+10],v[N+10],rnk[N+10],f[N+10],g[N+10];
void prepare(){
	for (int i=0;i<=N;i++){
		C[i][0]=1;
		for (int j=1;j<=i;j++)	C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
	}
}
int mlt(int a,int b){
	int res=1;
	for (;b;b>>=1,a=1ll*a*a%p)	if (b&1)	res=1ll*res*a%p;
	return res;
}
int main(){
	prepare();
	int n=read(),m=read(),k=read();
	for (int i=1;i<=m;i++)	v[i]=read();
	for (int i=1;i<=m;i++)	rnk[i]=read();
	for (int i=n-1;i;i--){
		f[i]=C[n-1][i];
		for (int j=1;j<=m;j++)	f[i]=1ll*f[i]*C[n-i-1][rnk[j]-1]%p;
		for (int j=i+1;j<n;j++)	f[i]=(f[i]-1ll*f[j]*C[j][i]%p+p)%p;
	}
	int Ans=f[k];
	for (int i=1;i<=m;i++){
		g[0]=v[i]%p;
		for (int j=1;j<=n;j++){
			int tmp=1-mlt(v[i]+1,j+1);
			for (int l=0;l<j;l++)	tmp=(tmp+1ll*C[j+1][l]*g[l])%p;
			g[j]=1ll*tmp*mlt(-1-j,p-2)%p;
		}
		int res=0;
		for (int k=0;k<rnk[i];k++)	res=(res+((rnk[i]-k-1)&1?-1ll:1ll)*C[rnk[i]-1][k]*mlt(v[i],k)%p*g[n-k-1]%p)%p;
		Ans=1ll*Ans*res%p;
	}
	printf("%d\n",(Ans+p)%p);
	return 0;
}
posted @ 2018-12-03 20:01  Wolfycz  阅读(210)  评论(0编辑  收藏  举报