AGC030D 题解
题目链接
是的,对我来说又是一道不可做题。。。
看到题目后对着题面发了 40 min 的呆,光荣想到 \(O(n2^q)\) 的指数级做法。
然后灵光一现,发现可能直接做做不出来,然后就花一天的时间胡了一个做法。
我们要求的是所有可能的逆序对的个数和,但这样显然是不对的。
我们考虑先求出进行任意操作后的逆序对的期望个数 \(Ans\) ,答案直接乘上 \(2^q\) 就可以了。
接着我们再拆分贡献,计算每两位 \(i\) 和 \(j\) 满足 \(i<j\) 并且 \(a_i>a_j\) 的期望。
那么总的期望就是所有上述情况的期望的总和。
我们设 \(\tt DP\) 状态 \(F(i,j)\) 表示第 \(i\) 位比第 \(j\) 位小的期望。
初始化非常简单 F[i][j] = (a[i] < a[j]);
最开始情况就是原数组的情况。
接下来枚举每一个可以交换的操作,为了方便我们把原题中的 \(x_i\) 和 \(y_i\) 用 \(l\) 和 \(r\) 表示。
可以发现,有 \(\frac{1}{2}\) 的概率会进行交换,所以最简单的一步是。
\[F(l,r)=F(r,l)=\frac{1}{2}\times(F(l,r)+F(r,l))
\]
接下来我们考虑只有一位是 \(l\) 或 \(r\) 的二元组 \((i,j)\) 。
很显然的是对于这样的二元组,可以按照上述的思路继续转移,因为不好描述,所以直接放代码。
for (int i = 1; i <= q; i++) {
int l = x[i], r = y[i];
f[l][r] = f[r][l] = inv * (f[l][r] + f[r][l]) % mod;
for (int j = 1; j <= n; j++) {
if (j == l || j == r) continue;
f[l][j] = f[r][j] = inv * (f[l][j] + f[r][j]) % mod;
f[j][l] = f[j][r] = inv * (f[j][l] + f[j][r]) % mod;
}
}
其中 \(\tt inv\) 表示 \(2\) 在模题目中模数时的逆元。
统计答案的话,直接按照 \(\tt DP\) 的状态枚举累加就可以了,能看懂状态的话就不难。
注意最后要乘上 \(2^q\) 求可以了。
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define quad putchar(' ')
#define Enter putchar('\n')
using std::abs;
using std::pair;
using std::string;
using std::make_pair;
#define int long long
template <class T> void read(T &a);
template <class T> void write(T x);
template <class T, class ...rest> void read(T &a, rest &...x);
template <class T, class ...rest> void write(T x, rest ...a);
const int N = 3005;
const int mod = 1e9 + 7;
int n, q, a[N], x[N], y[N], f[N][N];
inline int power(int a, int n) {
int ret = 1;
while (n) {
if (n & 1) ret = ret * a % mod;
a = a * a % mod; n /= 2;
} return ret;
}
signed main(void) {
read(n, q);
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 <= q; i++) read(x[i], y[i]);
int mul = power(2, q);
int inv = (mod + 1) / 2;
for (int i = 1; i <= q; i++) {
int l = x[i], r = y[i];
f[l][r] = f[r][l] = inv * (f[l][r] + f[r][l]) % mod;
for (int j = 1; j <= n; j++) {
if (j == l || j == r) continue;
f[l][j] = f[r][j] = inv * (f[l][j] + f[r][j]) % mod;
f[j][l] = f[j][r] = inv * (f[j][l] + f[j][r]) % mod;
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i - 1; j++) ans = (ans + f[i][j]) % mod;
write(ans * mul % mod); Enter;
return 0;
}
template <class T> void read(T &a) {
int s = 0, t = 1;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') c = getchar(), t = -1;
while (isdigit(c)) s = s * 10 + c - '0', c = getchar();
a = s * t;
}
template <class T> void write(T x) {
if (x == 0) putchar('0');
if (x < 0) putchar('-'), x = -x;
int top = 0, sta[50] = {0};
while (x) sta[++top] = x % 10, x /= 10;
while (top) putchar(sta[top] + '0'), top --;
return ;
}
template <class T, class ...rest> void read(T &a, rest &...x) {
read(a); read(x...);
}
template <class T, class ...rest> void write(T x, rest ...a) {
write(x); quad; write(a...);
}