AGC030D Inversion Sum

Inversion Sum

给你一个长度为 𝑛 的整数序列 𝐴。依次进行 𝑞 轮操作。第 𝑖 轮操作被描述为两个整数 𝑋𝑖 和 𝑌𝑖 。在每一轮操作中,我们将进行以下两种操作中的一种:

  • 交换 𝐴𝑋𝑖 和 𝐴𝑌𝑖
  • 什么也不做

因此,存在 2𝑞 种不同的方法来执行完所有的操作。每一种方法结束后都可以得到一个最终序列,询问对于所有 2𝑞 个最终序列,它们的各自的逆序对数之和是多少。答案对 109 + 7 取模。

𝑛, 𝑞 ≤ 3000。

题解

https://www.luogu.com.cn/blog/PinkRabbit/solution-at4513

因为 \(N\) 很小,考虑利用期望的线性性直接枚举位置对 \(\langle i, j \rangle\)\(1 \le i < j \le N\))以统计逆序对。

考虑一个概率 DP:令 \(f(i, j)\)\(1 \le i, j \le N\))为当前时刻下,\(A_i > A_j\) 的概率。
(这里假设对于 \(Q\) 个操作,每个操作都以 \(1 / 2\) 的概率执行)

那么最终时刻下,满足 \(i < j\)\(f(i, j)\) 之和,再乘以 \(2^Q\) 就是答案(期望的线性性)。

按顺序考虑每个时刻(操作),考虑新的 \(f(i, j)\) 和原先的比有什么变化。

可以发现只有 \(\mathcal O (N)\) 个位置会发生变化。具体地说,只有 \(i, j\) 有至少一个等于 \(X_i\)\(Y_i\) 时才有可能发生变化。

暴力转移即可。

时间复杂度为 \(\mathcal O (N (N + Q))\)

CO int N=3e3+10;
int A[N],F[N][N];

int main(){
	int n=read<int>(),m=read<int>();
	for(int i=1;i<=n;++i) read(A[i]);
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
		F[i][j]=A[i]>A[j];
	for(int i=1;i<=m;++i){
		int x=read<int>(),y=read<int>();
		F[x][y]=F[y][x]=mul(add(F[x][y],F[y][x]),i2);
		for(int j=1;j<=n;++j)if(j!=x and j!=y){
			F[x][j]=F[y][j]=mul(add(F[x][j],F[y][j]),i2);
			F[j][x]=F[j][y]=mul(add(F[j][x],F[j][y]),i2);
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)
		ans=add(ans,F[i][j]);
	ans=mul(ans,fpow(2,m));
	printf("%d\n",ans);
	return 0;
}

posted on 2020-04-22 10:14  autoint  阅读(150)  评论(0编辑  收藏  举报

导航