• 【BZOJ 3284】不等式


    题目

    这题太妙了,所以来写题解;

    注意到题目中的两个重要条件,(n imes tleq S,m-nleq 10^3);于是(sum_{i=1}^n x_i)一定不会超过(S);设这个和为(N),对于一个给定的(N),根据插板我们之后后面的方案数是(inom{S-N}{m-n})

    众所周知,(inom{x}{y})是一个关于(x)(y)次多项式,所以(inom{S-N}{m-n})一定可以写成(sum_{i=0}^{m-n}f_i(S-N)^i)的形式,((S-N)^i)可以根据二项式定理来展开,于是我们如果能对于(kin [0,m-n])求出每一种方案的(N^k)之和,即(sum_{1leq x_ileq t,ileq n}(x_1+x_2+dots +x_n)^k)就能快速计算答案了。

    显然可以倍增,用二项式定理合并答案,复杂度是(O((m-n)^2log n));其实也可以搞一个生成函数(F(x)=sum_{i=0}^{m-n}frac{sum_{j=1}^t j^i}{i!}x^i),求(F^n(x))即可,可以多项式exp,做到(O((m-n)^2)),但是由于我不会写暴力exp于是还是口胡一下就算了吧;

    代码,只能在dark上过

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    const int mod=1e9+7,maxn=1e3+5;
    inline int dqm(int x) {return x<0?x+mod:x;}
    inline int qm(int x) {return x>=mod?x-mod:x;}
    inline void upd(int &x,int y) {x+=y;if(x>=mod)x-=mod;}
    inline int ksm(int a,int b) {
    	int S=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)S=1ll*S*a%mod;return S;
    }
    LL Sum,lm;int n,m,ln,pre[maxn],pw[maxn],c[maxn][maxn];
    int A[maxn],h[maxn],g[maxn],fac[maxn],ifac[maxn],__pw[maxn][maxn];
    inline void Lagrange() {
    	if(!ln){h[0]=1;return;}h[1]=1;
    	for(re int i=1;i<ln;i++) 
    		for(re int j=i;j>=0;j--) {
    			upd(h[j+1],h[j]);
    			h[j]=1ll*h[j]*(mod-i)%mod;
    		}
    	for(re int i=0;i<=ln;i++) h[i]=1ll*h[i]*ifac[ln]%mod; 
    }
    inline int calc(int n,int k) {
    	for(re int i=0;i<=k+1;i++) pre[i]=__pw[i][k];
    	for(re int i=1;i<=k+1;++i) upd(pre[i],pre[i-1]);
    	if(n<=k+1) return dqm(pre[n]-(k==0));
    	int prd=1,tot=0;
    	for(re int i=0;i<=k+1;++i) prd=1ll*prd*dqm(n-i)%mod;
    	for(re int i=0;i<=k+1;++i) {
    		int v=1ll*prd*ksm(dqm(n-i),mod-2)%mod*pre[i]%mod;
    		v=1ll*ifac[i]*v%mod*ifac[k+1-i]%mod;
    		if((k+1-i)&1) v=dqm(-v);upd(tot,v);
    	}
    	return dqm(tot-(k==0));
    }
    inline void mul(int *B,int *C) {
    	for(re int nw=0,i=ln;i>=0;B[i]=nw,--i,nw=0) 
    		for(re int j=0;j<=i;++j)
    			upd(nw,1ll*B[i-j]*C[j]%mod*c[i][j]%mod); 
    }
    void solve(int n,int *f) {
    	if(n==1) {
    		for(re int i=0;i<=ln;++i) g[i]=f[i]=calc(lm%mod,i);
    		return;
    	}
    	solve(n>>1,f);mul(f,f);if(n&1)mul(f,g);
    } 
    int main() {
    	scanf("%lld%lld%d%d",&Sum,&lm,&n,&m);
    	ln=m-n+1;fac[0]=ifac[0]=1;
    	for(re int i=1;i<=ln;++i)fac[i]=1ll*fac[i-1]*i%mod;
    	ifac[ln]=ksm(fac[ln],mod-2);
    	for(re int i=ln-1;i;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    	for(re int i=0;i<=ln;i++)__pw[i][0]=1,c[i][0]=c[i][i]=1;
    	for(re int i=1;i<=ln;i++) 
    		for(re int j=1;j<=ln;++j) __pw[i][j]=1ll*__pw[i][j-1]*i%mod;
    	for(re int i=1;i<=ln;i++)
    		for(re int j=1;j<i;++j) c[i][j]=qm(c[i-1][j]+c[i-1][j-1]);
    	ln--;Lagrange();solve(n,A);int ans=0;Sum%=mod;
    	pw[0]=1;for(re int i=1;i<=ln;i++)pw[i]=1ll*pw[i-1]*Sum%mod;
    	for(re int i=0;i<=ln;++i) {
    		int nw=0;
    		for(re int j=0;j<=i;++j) 
    			upd(nw,1ll*pw[i-j]*A[j]%mod*c[i][j]%mod*(j&1?mod-1:1)%mod);
    		upd(ans,1ll*h[i]*nw%mod);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Linux文件管理系统
    添加硬盘分区
    SWPFILE实现(增加swap空间)
    磁盘配额
    javascript插件uploadify简单实现文件上传
    Java继承--子类的实例化过程
    Java继承--子父类中的构造函数
    Java继承--覆盖
    设计模式——单例设计模式
    在vim中,使用可视化拷贝(剪切)粘贴文本
  • 原文地址:https://www.cnblogs.com/asuldb/p/12506149.html
Copyright © 2020-2023  润新知