Loading

【题解】CF1542E2 Abnormal Permutation Pairs (hard version)

数数好题。

求二元组 \((p,q)\) 的数量使得 \(p,q\) 是长度为 \(n\) 排列,其中 \(p\) 的字典序更小,逆序对更多。

需要比字典序,我们枚举第一个不相同的的位置 \(i\) 。那么 \(i\) 前面的方案是 \(i!\binom{n}{i}\)

我们枚举第 \(i\) 位上 \(p,q\) 分别填的数是 \(l,r\) ,那么记对应后面的方案位 \(F_{n-i,r-l+1}\)

不难发现,我们要求的 \(F_{i,j}\) 就是二元组 \((u,v)\) 的数量,使得 \(u,v\) 是长度为 \(i\) 的排列,其中 \(u\) 的逆序对数比 \(v\) 的多 \(j\) 个。

这玩意看起来就比较阴间,我们转化为求 \(f_{i,j}\) 表示逆序对恰好多 \(j\) 个。

我们可以直接计算 \(g_{i,j}\) 表示长度为 \(i\),逆序对数为 \(j\) 的排列数,然后利用 \(g\) 来计算 \(f\),这样做时间复杂度是 \(\mathcal{O}(N^5)\),前缀和优化以下可以做到 \(\mathcal{O}(N^4)\) ,并且我手算了以下发现再计算一次前缀和并用卷积优化可以做到 \(\mathcal{O}(N^3\log N)\)

以上的复杂度仍然不足以通过。

由于计算 \(g\) 的复杂度已经到了极限,我们考虑直接计算 \(f\) ,不难发现枚举第 \(i\) 位上填的两个数,我们关心的只有这两个数的差。直接作差可以优化一维,时间复杂度是 \(\mathcal{O}(N^4)\),直接卷积可以做到 \(\mathcal{O}(N^3\log N)\)

再观察一下,发现我们求得大致是形如 \(f_{i,j}=\sum |j-k|\times f_{i-1,k}\) ,拆掉绝对值后,可以将贡献拆为 \(\sum\limits_{j} f_{i,j}\)\(\sum \limits_{j}j\times f_{i,j}\) 两部分(篇幅原因省略了系数),这两部分都可以通过前缀和求出来,所以直接前缀和优化可以做到 \(\mathcal{O}(N^3)\)

直接开空间开不下,需要滚动数组优化。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 1005
using namespace std;
int n,P,f[N * N * 2],g[N * N * 2],p[N * N * 2],c[N][N],fac[N],ss,ans;
inline void ad(int &x,int y){x=(x+y)%P;if(x<0)x+=P;}
void maintain(int lim){
	g[ss - lim] = f[ss - lim];
	p[ss - lim] = - lim * f[0] % P + P;
	rep(j,-lim + 1,lim)
		p[j + ss] = (p[j - 1 + ss] + 1LL * f[j + ss] * j % P + P) % P,
		g[j + ss] = (g[j - 1 + ss] + f[j + ss]) % P;
}
int get(int *u,int l,int r){
	if(l > r)return 0;
	return (u[r + ss] - u[l - 1 + ss] + P) % P;
}
void calc(){
	f[ss] = 1;maintain(0);
	rep(i, 1, n - 1){
		int cur =  i * (i - 1) / 2;
		rep(k, -cur , cur){
			int L = max(k - i + 1, -cur);
			int R = min(k + i - 1, cur);
			f[k + ss] = 1LL * i * get(g, L, R) % P; 
			ad(f[k + ss], (1LL * get(g, k + 1, R) * k - get(p, k + 1, R)) % P);
			ad(f[k + ss], (get(p, L, k) - 1LL * get(g, L, k) * k % P) % P);
		}
		maintain(i * (i + 1) / 2);
		int w = n - i;
		int sum = n - w + 1;
		int ins = 1LL * c[n][w - 1] * fac[w - 1] % P;
		rep(l, 1, sum)rep(r, l + 1, sum){
			int k = r - l + 1;
			ans = (ans + 1LL * ins * get(g, k, cur)) % P;
		}
	}
}
signed main(){
	scanf("%d%d",&n,&P);ss = n * (n - 1)/2;
	fac[0] =1;rep(i,1,n)fac[i]=1LL*fac[i-1]*i%P;
	rep(i,0,n){
		c[i][0]=1;
		rep(j,1,i)c[i][j] = (c[i - 1][j - 1] + c[i - 1][j])%P;
	}
	calc();printf("%d\n",ans);
	return 0;
}
posted @ 2021-07-04 09:40  7KByte  阅读(160)  评论(0编辑  收藏  举报