[AGC030D] Inversion Sum

发布时间 2023-08-25 18:09:50作者: -白简-

题目大意

一个长度为 \(n\) 的数列,然后给你 \(q\) 个交换或不交换操作,你可以选择操作或者不操作,问所有情况下逆序对的总和。

答案需要对 \(10 ^ 9 + 7\) 取模。

\(n\leq 3000\)\(q\leq 3000\))。

思路

这道题非常巧妙。

我们先考虑转化题意,求逆序对数量的期望。

\(dp_{i,j}\) 表示 \(a_i>a_j\) 的概率,初始值很好设,直接根据初始给出的排列情况进行赋值。

  • \(a_i>a_j\),则 \(dp_{i,j}=1\)
  • \(a_i < a_j\),则 \(dp_{j,i}=1\)

考虑如果我们交换 \(x\)\(y\) 的位置,会产生什么影响。对于 \(\forall i,j \in \left[ 1,n \right]\),其中 \(i,j\) 没有与 \(x\)\(y\) 的情况,不会影响 \(dp_{i,j}\) 的值。

\(f_{i,j}\) 表示未更改前的 \(dp\) 数组,考虑有 \(x,y\) 的情况,显然有

\[dp_{i,x}=\dfrac{f_{i,x}+f_{i,y}}{2} \]

\[dp_{i,y}=\dfrac{f_{i,x}+f_{i,y}}{2} \]

\[dp_{x,i}=\dfrac{f_{x,i}+f_{y,i}}{2} \]

\[dp_{y,i}=\dfrac{f_{x,i}+f_{y,i}}{2} \]

这道题求的是逆序对的总和,所以答案应当是所有情况数与逆序对数量的期望的乘积。

所以最后答案为

\[2^m \times \sum^{n}_{i=1}\sum^{n}_{j=i+1}dp_{i,j} \]

Code

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int Mod = 1e9 + 7;
const int N = 3050;

int n,m;

int a[N];

long long Pow(long long a ,long long b) {
    long long res = 1 ;
    long long base = a;
    while(b) {
   	    if(b & 1)
   		    res = res * base % Mod;
   	    base = base * base % Mod;
   	    b >>= 1;
   }
   return res;
}

long long Inv(int x) {
    return Pow(x,Mod - 2) % Mod;
}

long long dp[N][N],ans = 0;

signed main() {
    cin >> n >> m;
    for(int i = 1;i <= n; i++) 
        cin >> a[i];
    
    for(int i = 1;i <= n; i++) {
        for(int j = 1;j <= n; j++) {
            if(a[i] > a[j])
                dp[i][j] = 1;
        }
    }

    for(int i = 1,x,y;i <= m; i++) {
        cin >> x >> y;

        for(int i = 1;i <= n; i++) {
            if(i == x || i == y)
                continue;
            
            dp[i][x] = dp[i][y] = (dp[i][x] + dp[i][y]) * Inv(2) % Mod;
            dp[x][i] = dp[y][i] = (dp[x][i] + dp[y][i]) * Inv(2) % Mod;
        }

        dp[x][y] = dp[y][x] = (dp[x][y] + dp[y][x]) * Inv(2) % Mod;
    }

    for(int i = 1;i <= n; i++) 
        for(int j = i + 1;j <= n; j++) 
            ans = (ans + dp[i][j]) % Mod;

    ans = 1ll * ans * Pow(2,m) % Mod;

    cout << ans << "\n";
    return 0;
}