• [2017 山东一轮集训 Day7] 逆序对


    一、题目

    点此看题

    这么简单的去重我竟然没想到,我是个哈批。

    二、解法

    首先有一个显然的 (dp),依次加入 (1)(i),每次考虑逆序对的增量:

    [dp[i][j+k]leftarrow dp[i-1][j] kin[0,i) ]

    这个可以用前缀和优化,时间复杂度 (O(n^2)),可以写成生成函数的形式:

    [prod_{i=1}^nsum_{j=0}^ix^j=prod_{i=1}^nfrac{1-x^{i}}{1-x} ]

    分母并不需要多项式求逆,可以直接最后隔板法组合意义算,问题是 (prod 1-x^i) 的计算,这个算式从容斥的角度也可以解释,也就是钦定一个位置的逆序对不合法就会带来 (-1) 的容斥系数。

    因为我多项式学得太差了所以只会 (dp),考虑钦定位置的个数要 (leqsqrt {2k}) 才有可能有方案,发现这个东西就是柱状图 (dp) 板子,考虑有若干个柱子,每次可以新增一个柱子或者把所有柱子增加 (1) 的高度,那么转移,设 (dp[i][j]) 表示有 (i) 个柱子,柱子的总高度是 (j),我们从小到大枚举 (j)

    [dp[i][j]leftarrow dp[i-1][j-i]+dp[i][j-i] ]

    但是会算重,因为如果出现高度为 (n+1) 的柱子就不合法,那么直接减去这种方案即可:

    [dp[i][j]leftarrow dp[i][j]-dp[i-1][j-n-1] ]

    (f(t)) 为不定方程 (x_1+x_2..+x_n=t) 的不定整数解个数,那么答案式长这样:

    [sum_isum_j(-1)^icdot dp[i][k-j]cdot f(j) ]

    时间复杂度 (O(nsqrt n))

    #include <cstdio>
    #include <cmath>
    const int M = 100005;
    const int MOD = 1e9+7;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,dp[500][M],fac[2*M],inv[2*M],ans;
    void init(int n)
    {
    	fac[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
    	for(int i=2;i<=n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD;	
    }
    int C(int n,int m)
    {
    	if(n<m || m<0) return 0;
    	return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
    }
    int cal(int x)
    {
    	return C(x+n-1,n-1);
    }
    signed main()
    {
    	//freopen("perm.in","r",stdin);
    	//freopen("perm.out","w",stdout);
    	n=read();k=read();init(2e5);
    	dp[0][0]=1;m=499;
    	for(int i=1;i<=m;i++)
    	{
    		for(int j=i;j<=k;j++)
    		{
    			dp[i][j]=(dp[i-1][j-i]+dp[i][j-i])%MOD;
    			if(j>=n+1) dp[i][j]=(dp[i][j]-dp[i-1][j-n-1])%MOD; 
    		} 
    	}
    	for(int i=0;i<=m;i++)
    		for(int j=0;j<=k;j++)
    		{
    			int f=(i%2?-1:1);
    			ans=(ans+1ll*f*dp[i][k-j]*cal(j))%MOD;
    		}
    	printf("%lld
    ",(ans+MOD)%MOD);
    }
    
  • 相关阅读:
    mysql联合主键,也就是两个数据字段一起做主键的情况
    PHP细节,empty,is_null,isset,if()
    PHP细节,PHP手册中常见的一句话:该函数是二进制安全的
    git和github的学习
    用WPS查看两篇word文档异同之处
    js全角字符转为半角字符
    坑(十七)—— Linux无法挂载NTFS格式的U盘
    subprocess模块
    吴裕雄--天生自然--Go 语言学习笔记--Go 语言数组
    吴裕雄--天生自然--Go 语言学习笔记--Go 语言变量作用域
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15117964.html
Copyright © 2020-2023  润新知