zoukankan      html  css  js  c++  java
  • 【LOJ #6077】「2017 山东一轮集训 Day7」逆序对(生成函数+DP)

    传送门

    f[i][j]f[i][j]ii个数,逆序对数位jj的方案数
    显然枚举ii放在哪里可以得到dpdp

    f[i][j]=k=0min(i1,j)fi1,jkf[i][j]=sum_{k=0}^{min(i-1,j)}f_{i-1,j-k}
    写成生成函数的形式
    实际上就是i=0n1(j=0ixi)prod_{i=0}^{n-1}(sum_{j=0}^ix^i)
    =i=1n(1xi)(1x)n=frac{prod_{i=1}^{n}(1-x^i)}{(1-x)^n}
    1(1x)nfrac{1}{(1-x)^n}的系数很好求
    ii项为(i+n1n1){i+n-1choose n-1}

    考虑上面i=1n(1xi)prod_{i=1}^{n}(1-x^i)
    xnx^n系数的组合意义就是从1n1-n中选jj个数使得和为nn的方案乘上(1)j(-1)^j之和

    考虑DPDPf[i][j]f[i][j]表示选ii个数使得和为jj的方案
    显然选的数的个数mm满足m(m+1)2nm*(m+1)le 2*n
    mm最多就是450450左右

    考虑dpdp选出来的数排序后的差分序列
    那么dpdp方式和Y小Y的背包计数问题类似
    要么新加入一个11,要么给之前每个数加1
    注意要减去最后一个数大于了nn的情况

    复杂度O(nn)O(nsqrt n)

    #include<bits/stdc++.h>
    using namespace std;
    #define cs const
    #define re register
    #define pb push_back
    #define pii pair<int,int>
    #define ll long long
    #define fi first
    #define se second
    #define bg begin
    cs int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ib==ob)?EOF:*ib++;
    }
    inline int read(){
        char ch=gc();
        int res=0;bool f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
    template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
    cs int mod=1e9+7;
    inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
    inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
    inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
    inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
    inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
    inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
    inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
    inline int Inv(int x){return ksm(x,mod-2);}
    cs int N=200005;
    int fac[N],ifac[N];
    inline void init_inv(cs int len=N-5){
    	fac[0]=ifac[0]=1;
    	for(int i=1;i<=len;i++)fac[i]=mul(fac[i-1],i);
    	ifac[len]=Inv(fac[len]);
    	for(int i=len-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
    }
    inline int C(int n,int m){
    	return n<m?0:mul(mul(fac[n],ifac[m]),ifac[n-m]);
    }
    int m,f[2][100005],s[100005],n,k,cur;
    int main(){
    	#ifdef Stargazer
    	freopen("lx.in","r",stdin);
    	#endif
    	init_inv();
    	n=read(),k=read();
    	m=450;
    	f[0][0]=1;
    	s[0]++;
    	for(int i=1;i<=m;i++){
    		cur^=1;
    		memset(f[cur],0,sizeof(f[cur]));
    		for(int j=i;j<=k;j++){
    			Add(f[cur][j],add(f[cur][j-i],f[cur^1][j-i]));
    			if(j>n)Dec(f[cur][j],f[cur^1][j-n-1]);
    		}
    		for(int j=i;j<=k;j++){
    			if(i&1)Dec(s[j],f[cur][j]);
    			else Add(s[j],f[cur][j]);
    		}
    	}
    	int ret=0;
    	for(int i=0;i<=k;i++)Add(ret,mul(s[i],C(k-i+n-1,n-1)));
    	cout<<ret;
    }
    
    
  • 相关阅读:
    Linux下Mysql自启动
    C++的Vector用法
    如何判断一个文本文件内容的编码格式 UTF-8 ? ANSI(GBK)
    windows自带记事本导致文本文件(UTF-8编码)开头三个字符乱码问题
    C/C++字符串查找函数
    C++ string 字符串查找匹配
    CentOS6.5升级autoconf版本 Autoconf version 2.64 or higher is required
    Linux命令之远程下载命令:wget
    Linux常用命令大全
    如何使用VisualStudio2013编写和调试c语言程序
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328316.html
Copyright © 2011-2022 走看看