• BZOJ.4559.[JLOI2016]成绩比较(DP/容斥 拉格朗日插值)


    BZOJ
    洛谷

    为什么已经9点了...我写了多久...

    求方案数,考虑DP...
    (f[i][j])表示到第(i)门课,还有(j)人会被碾压的方案数。
    那么$$f[i][j]=sum_{k=j}^{n-1}f[i-1][k] imes C_k^{k-j} imes C_{n-1-k}^{R_i-1-(k-j)} imes g[i]$$

    就是先从(k)人中选出(k-j)(i)这门课比B神得分高,然后再从剩下(n-1-k)个人中选(R_i-1-(k-j))个比B神得分高的。
    对于排名限制,(g[i])表示对(i)这门课分配得分使得有(R_i-1)个人得分比B神高的方案数。直接枚举一下B神得分:$$g[i]=sum_{j=1}^{U_i}j^{n-R_i}(U_i-j)^{R_i-1}$$

    不难看出这是一个关于(U_i)(n)次的多项式。拉格朗日插值算一下就好了。
    (不对为啥是(n)次的不是(n-1)次的啊QAQ求路过dalao解答QAQ)(因为多一个(sum)?)

    复杂度(O(n^3log n))
    因为求(g)在某点的值的时候要(n)次快速幂。。看了半天题解也没看懂怎么优化掉这个。但是有更好的做法:here or here,是(n^3)的。
    不管了反正这个(log)也不大。
    用容斥做也可以,瓶颈也是在于求(g)。。

    //912kb	592ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define mod 1000000007
    #define Mod(x) x>=mod&&(x-=mod)
    #define Add(x,v) (x+=v)>=mod&&(x-=mod)
    typedef long long LL;
    const int N=105;
    
    int ifac[N],y[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline int FP(int x,int k)
    {
    	int t=1;
    	for(; k; k>>=1,x=1ll*x*x%mod)
    		if(k&1) t=1ll*t*x%mod;
    	return t;
    }
    int Lagrange(int *y,const int n,const int x)
    {
    	static int pre[N],suf[N];
    	pre[0]=x, suf[n+1]=1;
    	for(int i=n; i; --i) suf[i]=1ll*suf[i+1]*(x+mod-i)%mod;
    	for(int i=1; i<n; ++i) pre[i]=1ll*pre[i-1]*(x+mod-i)%mod;
    	LL ans=0;
    	for(int i=0,up,down; i<=n; ++i)
    	{
    		if(i) up=1ll*pre[i-1]*suf[i+1]%mod*y[i]%mod;
    		else up=1ll*suf[i+1]*y[i]%mod;
    		down=(n-i)&1?mod-1ll*ifac[i]*ifac[n-i]%mod:1ll*ifac[i]*ifac[n-i]%mod;
    		ans+=1ll*up*down%mod;
    	}
    	return ans%mod;
    }
    
    int main()
    {
    	static int C[N][N],f[N][N],U[N],R[N];
    
    	int n=read(),m=read(),K=read(),fac=1;
    	for(int i=2; i<=n; ++i) fac=1ll*fac*i%mod;
    	ifac[n]=FP(fac,mod-2);
    	for(int i=n; i; --i) ifac[i-1]=1ll*ifac[i]*i%mod;
    	C[0][0]=1;//!
    	for(int i=1; i<=n; ++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(C[i][j]);
    	}
    	for(int i=1; i<=m; ++i) U[i]=read();
    	for(int i=1; i<=m; ++i) R[i]=read();
    
    	f[0][n-1]=1;
    	for(int i=1; i<=m; ++i)
    	{
    		int Ri=R[i];
    		for(int x=1; x<=n; ++x)
    		{
    			LL tmp=0;
    			for(int j=1; j<=x; ++j) tmp+=1ll*FP(j,n-Ri)*FP(x-j,Ri-1)%mod;//这里j要枚举到x,因为0^0=1!...
    			y[x]=tmp%mod;
    		}
    		int g=Lagrange(y,n,U[i]);
    		for(int j=K; Ri+j<=n; ++j)
    		{
    			LL tmp=0;
    			for(int k=j; k<n; ++k)
    				if(k-j<Ri) tmp+=1ll*f[i-1][k]*C[k][j]%mod*C[n-1-k][Ri-1-k+j]%mod;
    				else break;
    			f[i][j]=tmp%mod*g%mod;
    		}
    	}
    	printf("%d
    ",f[m][K]);
    
    	return 0;
    }
    
  • 相关阅读:
    IOS 关于分辨率的那点事
    IOS多线程编程之NSOperation和NSOperationQueue的使用
    UI应遵循的三大网站设计原则
    Xcode 4.4中LLVM compiler 4.0带来的ObjectiveC新语法特性
    iPhone实战:操作SQLite
    flock()函数使用示例
    libtool: syntax error near unexpected token `]*'
    求职简历撰写要点
    thrift的js客户端收到含汉字字符中显示为乱码解决方法
    多写引发的思考
  • 原文地址:https://www.cnblogs.com/SovietPower/p/10246773.html
Copyright © 2020-2023  润新知