题解:P4223 期望逆序对
stripe_python · · 题解
模拟赛 T4 弱化版,拼尽全力只能写出暴力 DP /ll。
下面,我们给出一个基于 DP 优化的,不需要讨论
记
- 选择与
x,y 不相关:f_{i-1,x,y} \times \frac{(n-2)(n-3)}{2}\to f_{i,x,y} 。 - 选择了
x 但不选y :\sum \limits_{z \ne y}f_{i-1,x,z} \to f_{i,x,y} 。 - 选择了
y 但不选x :\sum \limits_{z \ne x} f_{i-1,z,y} \to f_{i,x,y} 。 - 同时选择
x,y :f_{i-1,y,x} \to f_{i,x,y} 。
我们不妨在最后再让
直接做为
:::::info[50pts 代码]
const int N = 505;
int n, k, a[N];
mint f[2][N][N], r[N], c[N];
void _main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) f[0][i][j] = a[i] > a[j];
const mint p = ~mint(n) * ~mint(n - 1) * 2, i2 = ~mint(2);
for (int T = 1, st = 1; T <= k; T++, st ^= 1) {
for (int i = 1; i <= n; i++) r[i] = accumulate(f[st ^ 1][i] + 1, f[st ^ 1][i] + n + 1, mint(0));
for (int j = 1; j <= n; j++) {
c[j] = 0;
for (int i = 1; i <= n; i++) c[j] += f[st ^ 1][i][j];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) continue;
f[st][i][j] = f[st ^ 1][i][j] * (n - 2) * (n - 3) * i2;
f[st][i][j] += r[i] - f[st ^ 1][i][j];
f[st][i][j] += c[j] - f[st ^ 1][i][j];
f[st][i][j] += f[st ^ 1][j][i];
f[st][i][j] *= p;
}
}
}
mint res = 0;
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++) res += f[k & 1][i][j];
cout << res * (~p).pow(k);
}
:::::
以上是赛时会了的。以下是赛后问 Gemini 会的。
记
我们来观察一下性质:
性质 1 当
性质 2
:::::success[性质 2 的证明]
将性质 1 代入
:::::
性质 3
:::::success[性质 3 的证明]
根据性质 1,在矩阵
考虑
根据性质 2,我们只需计算
我们发现,
解一阶线性递推得
:::::success[怎么解]
记
将原递推式与
我们构造了一个以
移项得解。 :::::
我们写出整体期望
代入性质 2 和
我们有
解关于
求出初始逆序对数
const int N = 5e5 + 5;
int n, k, a[N];
struct BIT {
int tr[N];
void add(int x, int c) {
for (; x <= n; x += lowbit(x)) tr[x] += c;
}
int ask(int x) {
int res = 0;
for (; x >= 1; x -= lowbit(x)) res += tr[x];
return res;
}
} B;
void _main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
if (n == 1) return cout << 0, void();
const mint i2 = ~mint(2), n5 = mint(n - 5) / (n - 1), n3 = mint(n - 3) / (n - 1), c2 = mint(n) * (n - 1) / 2;
mint e0 = 0;
for (int i = 1; i <= n; i++) B.add(a[i], 1), e0 += i - B.ask(a[i]);
mint C = 0;
for (int i = 1; i <= n; i++) C += (a[i] - 1 - (n - 1) * i2) * (n - 2 * i + 1);
mint ek = n5.pow(k) * e0 + c2 * (1 - n5.pow(k)) / 2 + (C * (n3.pow(k) - n5.pow(k))) / n;
cout << ek * c2.pow(k);
}
Bonus:模拟赛 T4 在这个基础上套个 P12685 就是正解。二合一觉得自己很牛吗。