BZOJ4559 成绩比较

题目传送门

分析:
我们可以先试着求一下,对于单个学科,有多少种分配方案可以使B神排名为R
对于第i个学科

\(~~~~g(i)=\sum_{j=1}^{H_i}j^{n-R_i}(H_i-j)^{R_i-1}\)

相当于枚举B神本人的分数,然后分别将其他人分配
这个\(H_i\)很大,但是这个函数是一个大约在n次的多项式,拉格朗日插值一下就好了
不会?去百度一下,就是套一个公式2333
然后我们考虑DP
设f[i][j]表示前i个技能后目前碾压了j个人
那么

\(~~~~f[i][j]=\sum_{k=j}^{n-1}f[i-1][k]C_k^jC_{n-k-1}^{R_i-1-k+j}g(i)\)

相当于是在前i-1个技能中碾压的k个人里面选择j个,剩下的n-k-1再选R[i]-1-k+j,一共j个人被碾压
然后大力DP

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>

#define maxn 105
#define MOD 1000000007

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
long long H[maxn],R[maxn];
long long f[maxn][maxn],g[maxn];
long long C[maxn][maxn];

inline long long ksm(long long num,long long k)
{
	long long ret=1;
	for(;k;k>>=1,num=num*num%MOD)if(k&1)ret=ret*num%MOD;
	return ret;
}

inline long long lagrange(int x)
{
	long long ret=0;
	long long tmp[maxn];memset(tmp,0,sizeof tmp);
	for(int h=0;h<maxn;h++)for(int i=1;i<=h;i++)
		(tmp[h]+=ksm(i,n-R[x])*ksm(h-i,R[x]-1))%=MOD;
	for(int i=0;i<maxn;i++)
	{
		long long num=1;
		for(int j=0;j<maxn;j++)if(i!=j)num=num*(H[x]-j)%MOD*ksm((i-j+MOD)%MOD,MOD-2)%MOD;
		(ret+=tmp[i]*num)%=MOD;
	}
	return (ret+MOD)%MOD;
}

int main()
{
	n=getint(),m=getint();int p=getint();
	for(int i=1;i<=m;i++)H[i]=getint();
	for(int i=1;i<=m;i++)R[i]=getint();
	for(int i=1;i<=m;i++)g[i]=lagrange(i);
	for(int i=0;i<maxn;i++)
	{
		C[i][0]=C[i][i]=1;
		for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
	}
	f[0][n-1]=1;
	for(int i=1;i<=m;i++)for(int j=0;j<n;j++)for(int k=j;k<n;k++)
		if(R[i]-1-k+j>=0&&n-1-k>=R[i]-1-k+j)
		(f[i][j]+=f[i-1][k]*C[k][j]%MOD*C[n-k-1][R[i]-1-(k-j)]%MOD*g[i])%=MOD;
	printf("%lld\n",f[m][p]);
}

posted @ 2020-01-30 16:45  Izayoi_Doyo  阅读(131)  评论(0编辑  收藏  举报