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;
}