• [BZOJ4559][JLOI2016]成绩比较


    bzoj
    luogu

    description

    (n)名学生(m)门课,(mbox{yyb})碾压了(k)名同学(即每门课的分数都大于等于那名同学的分数)。
    已知每门课(mbox{yyb})的排名(R_i)和这门课的最高分(U_i)(分数区间是([1,U_i])),求有多少种可能的得分情况。
    (n,mle100,U_ile10^9)

    sol

    设有(k)名同学没有被(mbox{yyb})碾压,所以这(k)名同学至少要有一门比(mbox{yyb})要高。
    每一门科目可以有(R_i-1)个人比(mbox{yyb})要高。
    容斥一下,枚举(k)个人中有(i)个人没有一门比(mbox{yyb})

    [ans=sum_{i=0}^k(-1)^iinom{k}{i}prod_{j=1}^{m}inom{k-i}{R_j-1} ]

    但是这样算出来的只是每个人与(mbox{yyb})的相对分数的方案数,没有计算具体分数。
    在计算具体分数的方案数时,显然每门课可以单独考虑。
    对于第(i)门课,考虑枚举(mbox{yyb})的分数(x),那么满足条件的方案数就是

    [sum_{x=1}^{U_i}x^{n-R_i}(U_i-x)^{R_i-1} ]

    这是一个关于(U_i)(n)次多项式,所以直接插值就可以了。
    复杂度(O(n^3log n))然而网上很多题解的复杂度都远优于这个qwq

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int mod = 1e9+7;
    const int N = 105;
    int n,m,k,U[N],R[N],C[N][N],inv[N],f[N],ans;
    int fastpow(int a,int b){
    	int res=1;
    	while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    	return res;
    }
    int main(){
    	n=gi();m=gi();k=n-1-gi();
    	for (int i=1;i<=m;++i) U[i]=gi();
    	for (int i=1;i<=m;++i) R[i]=gi();
    	C[0][0]=1;
    	for (int i=1;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])%mod;
    	}
    	inv[0]=inv[1]=1;
    	for (int i=2;i<=n;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    	for (int i=0;i<=k;++i){
    		int res=C[k][i];
    		for (int j=1;j<=m;++j) res=1ll*res*C[k-i][R[j]-1]%mod;
    		if (i&1) res=mod-res;(ans+=res)%=mod;
    	}
    	for (int i=1;i<=m;++i){
    		int res=0;
    		for (int j=1;j<=n;++j){
    			f[j]=0;
    			for (int k=1;k<=j;++k)
    				f[j]=(f[j]+1ll*fastpow(k,n-R[i])*fastpow(j-k,R[i]-1))%mod;
    		}
    		if (U[i]<=n) {ans=1ll*ans*f[U[i]]%mod;continue;}
    		for (int j=1;j<=n;++j){
    			int s=f[j];
    			for (int k=0;k<=n;++k)
    				if (k!=j) s=1ll*s*(U[i]-k)%mod*(j>k?inv[j-k]:mod-inv[k-j])%mod;
    			(res+=s)%=mod;
    		}
    		ans=1ll*ans*res%mod;
    	}
    	printf("%lld
    ",1ll*ans*C[n-1][k]%mod);return 0;
    }
    
  • 相关阅读:
    iOS 11: CORE ML—浅析
    Android 平台 Native 代码的崩溃捕获机制及实现
    H5直播避坑指南
    Mac系统升级至OS X Mavericks后Genymotion出现的问题及解决方法
    Android 4.4 KitKat终于支持录屏(Screen Recording)了!
    Android开发者资源大汇总
    用AndroidSDK中的Face Detector实现人脸识别
    [Android设计模式]Android退出应用程序终极方法
    ActionBarCompat 教程-实现Action Bar
    使用Roboguice依赖注入规划Android项目
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9387667.html
Copyright © 2020-2023  润新知