zoukankan      html  css  js  c++  java
  • BZOJ4559&P3270[JLoi2016]成绩比较

    题目描述

    (G)系共有(n)位同学,(M)门必修课。这(N)位同学的编号为(0)(N-1)的整数,其中(B)神的编号为(0)号。这(M)门必修课编号为(0)(M-1)的整数。一位同学在必修课上可以获得的分数是(1)(U_i)中的一个整数。
    如果在每门课上(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)的余数就可以了。

    输入格式

    第一行包含三个正整数(N,M,K),分别表示(G)系的同学数量(包括(B)神),必修课的数量和被(B)神碾压的同学数量。
    第二行包含(M)个正整数,依次表示每门课的最高分(U_i)
    第三行包含(M)个正整数,依次表示(B)神在每门课上的排名(Ri)。保证(1 le R_i le N)
    数据保证至少有1种情况使得(B)神说的话成立。

    输出格式

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

    输入输出样例

    输入 #1

     3 2 1
     2 2
     1 2
    

    输出 #1

     10
    

    根据题意,同学们是互不相同的。那么既然(k) 名同学被(B)神碾压,方案数便是(C^k_{n-1})
    然后(n-k-1)(()记为(num)())名同学是没有被(B)神碾压的,所以每人都至少有一科比(B)神高。已知(B)神每一科的排名(R_k),考虑比(B)神这科分数高的人的方案,为(C^{Rk-1}_{num})
    (m) 科一起算,方案数为$$prod_{k=1}^{m} {C^{R_k-1}_{num}}$$
    但上述有个问题,按上面的方法,(num)人中可能有人没有一科比(B)神高,所以
    容斥一下。得

    [T=sum_{i=0}^{num}(-1)^{num-i} C_{num}^i T_{i} ]

    [=sum_{i=0}^{num}(-1)^{num-i} C_{num}^iprod_{k=1}^{m} {C^{R_k-1}_{i}} ]

    那么到现在 (C^{k}_{n-1}T) 即为同学比B神的成绩相对大小的方案数。不过还没有考虑分数的问题。
    先考虑单科,考虑某一科满足B神排名为 (Ri) 的方案数。
    首先,(n) 个同学分布在 (x) 分内的方案显然为 (x^n) (最低为1分,开始我没好好读题以为可以有0分卡了好久),因为我们只是考虑同学与B神的分数高低方案,同学间的高低没算在内,所以不是组合数形式...
    因为 (Ri-1) 名同学必须严格大于B神,(n-Ri) 名同学是小于等于B神,所以不能简单乘一乘,那就枚举b神的分数

    [Si=sum_{x=1}^{Ui} x^{n-Ri}(Ui-x)^{Ri-1} ]

    这显然会T,因为 (Ui) 很大。
    所以根据经验就乱搞一下———把后面的((Ui-x)^{Ri-1})展开应该会很不错。然后交换一下求和的顺序。

    [Si=sum_{x=1}^{Ui} x^{n-Ri}(Ui-x)^{Ri-1}$$ $$=sum_{x=1}^{Ui} x^{n-Ri} sum_{t=0}^{Ri-1}(-1)^t C^t_{Ri-1}Ui^{Ri-1-t}x^t$$ $$=sum_{x=1}^{Ui} sum_{t=0}^{Ri-1}(-1)^t C^t_{Ri-1}Ui^{Ri-1-t}x^t x^{n-Ri}$$ $$= sum_{t=0}^{Ri-1}(-1)^t C^t_{Ri-1}Ui^{Ri-1-t}sum_{x=1}^{Ui}x^{n-Ri+t} ]

    那么这个东西就可求了。求出 (sum_{x=1}^{Ui}x^{n-Ri+t})就可以了。
    怎么就可求了呢?
    考虑如何求(1^2+2^2+3^2+4^2+...+n^2)的值。其中一种方法为:
    (Tn=(n+1)^3-n^3),有

    [Tn=(n+1)^3-n^3=3n^2+3n+1 ]

    然后显然的是  
    

    [sum_{i=1}^n Ti=(n+1)^3-n^3+n^3-(n-1)^3+...-1^3$$ $$=(n+1)^3-1 ]

    根据上面还有  
    

    [sum_{i=1}^n Ti=3 sum_{i=1}^n i^2+3sum_{i=1}^ni+sum_{i=1}^n1 ]

    [1^2+2^2+3^2+4^2+...+n^2=frac{(n+1)^3-1-3sum_{i=1}^ni+sum_{i=1}^n1}{3} ]

    所以对于 (1^t+2^t+3^t+...+n^t) 可以用类似方法求。把这个数列记为 (X_t^n),则有

    [(n+1)^{t+1}-1=sum_{i=0}^t C_{t+1}^{t-i+1} X_i^n ]

    [X_t^n=frac{(n+1)^{t+1}-1-sum_{i=0}^{t-1} C_{t+1}^{t-i+1}X_i^n}{C_{t+1}^{1}}=frac{(n+1)^{t+1}-1-sum_{i=0}^{t-1} C_{t+1}^{t-i+1}X_i^n}{t+1} ]

    [X_0^n=n ]

    可以在(O(t^2))时间内得到 (X)
    认真考虑一下,好像没有别的了。当然乘一起。

    [ans=C^k_{n-1}Tprod_{i=1}^m Si$$ $$=C^k_{n-1}(sum_{i=0}^{num}(-1)^{num-i}C_{num}^i prod_{k=1}^{m} {C^{R_k-1}_{i}})prod_{i=1}^m sum_{t=0}^{Ri-1}(-1)^t C^t_{Ri-1}Ui^{Ri-1-t}X_{n-Ri+t}^{Ui} ]

    复杂度(O(mn^2)),主要在于处理 (X)

    #include <cstdio>
    #define max(a,b) (a)>(b)?(a):(b)
    using namespace std;
    
    const int MAXN=233;
    const long long mod=1000000007;
    int n,m,nm,num,k;
    long long fac[MAXN],Inv[MAXN],inv[MAXN],U[MAXN],R[MAXN],x[MAXN][MAXN];
    
    inline long long qpow(long long a,long long b,long long mod)
    {
    	long long res=1;
    	while (b)
    	{
    		if (b&1) res=res*a%mod;
    		a=a*a%mod;b>>=1;
    	}
    	return res;
    }
    
    inline void take_table()
    {
    	fac[0]=1;inv[1]=1;
    	for (int i=1;i<=nm+10;i++) fac[i]=1ll*fac[i-1]*i%mod;
    	Inv[nm+10]=qpow(fac[nm+10],mod-2,mod);
    	for (int i=nm+10;i>=1;i--) Inv[i-1]=1ll*Inv[i]*i%mod;
    	for (int i=2;i<=nm+10;i++) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    }
    
    inline long long comb(long long n,long long m)
    {
    	if (n==m) return 1;
    	return 1ll*fac[n]*Inv[m]%mod*Inv[n-m]%mod;
    }
    
    inline long long A()
    {
    	long long res,ans=0;
    	for (int i=num,f=-1;i>=0;i--)
    	{
    		res=1;f=-f;
    		for (int j=1;j<=m;j++) res=res*comb(i,R[j]-1)%mod;
    		ans=(ans+res*f*comb(num,i)+mod)%mod;
    	}
    	return ans;
    }
    
    inline long long B()
    {
    	long long res,fina=1,ans;
    	for (int i=1;i<=m;i++)
    		for (int j=0;j<=n;j++)
    		{
    			res=0;
    			for (int k=0;k<=j-1;k++) res=(res+1ll*x[i][k]*comb(j+1,j-k+1)%mod)%mod;
    			x[i][j]=1ll*(qpow(U[i]+1,j+1,mod)-1-res+mod)%mod*1ll*inv[j+1]%mod;
    		}
    	for (int i=1;i<=m;i++)
    	{
    		ans=0;
    		for (int j=0,f=1;j<R[i];j++,f=-f)
    			ans=(ans+f*comb(R[i]-1,j)*qpow(U[i],R[i]-j-1,mod)%mod*x[i][n-R[i]+j]%mod+mod)%mod;
    		fina=(fina*ans%mod+mod)%mod;
    	}
    	return fina;
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);num=n-k-1;nm=max(n,m);
    	for (int i=1;i<=m;i++) scanf("%lld",&U[i]);
    	for (int i=1;i<=m;i++) scanf("%lld",&R[i]);
    	take_table();
    	printf("%lld
    ",A()*B()%mod*comb(n-1,k)%mod);
    	return 0;
    }
    
  • 相关阅读:
    12-14面向对象--抽象基类、接口、委托
    关于 try catch catch
    C# using 三种使用方式
    互斥锁(Mutex)
    C#中Monitor类、Lock关键字和Mutex类
    System.Data.SQLite
    Dictionary<TKey, TValue> 类
    AttributeTargets 枚举
    C# is和as操作符
    合并委托(多路广播委托)
  • 原文地址:https://www.cnblogs.com/lzxzy-blog/p/11395188.html
Copyright © 2011-2022 走看看