[题解] [AGC030D] Inversion Sum

题面

题解

如果我们知道在这 \(2^p\) 种方案中, 每一对 \(i, j\) 满足 \(i < j\)\(a_i > a_j\) 的方案数
那么我们把所有的加起来就行了
考虑 DP 这样一个东西
\(f[i][j]\)\(i\) 位置上的数大于 \(j\) 位置上的数的概率
假设每一次操作有 \(\frac{2}{1}\) 的概率进行, 否则不进行
那么 \(q\) 次操作完之后 \(f[i][j] * 2 ^ p\) 就是 \(i\) 位置上的数大于 \(j\) 位置上的数的期望方案的个数
然后考虑一次操作 \(x, y\), 只会改变 \(O(n)\) 个状态
转移方程是

\[f[x][i] = (f[x][i] + f[y][i]) / 2 \]

自己想一想为什么
复杂度为 \(O(n * q)\)
妙啊

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 3e3 + 5;
const int mod = 1e9 + 7;
const int inv = 5e8 + 4; 
using namespace std; 

int n, q, a[N], f[N][N], ans; 

template < typename T >
inline T read()
{
	T x = 0, w = 1; char c = getchar();
	while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * w; 
}

int fpow(int x, int y)
{
	int res = 1;
	for( ; y; y >>= 1, x = 1ll * x * x % mod)
		if(y & 1) res = 1ll * res * x % mod;
	return res; 
}

int main()
{
	n = read <int> (), q = read <int> ();
	for(int i = 1; i <= n; i++)
		a[i] = read <int> ();
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			f[i][j] = a[i] > a[j]; 
	for(int x, y, i = 1; i <= q; i++)
	{
		x = read <int> (), y = read <int> ();
		f[x][y] = f[y][x] = 1ll * (f[x][y] + f[y][x]) % mod * inv % mod; 
		for(int j = 1; j <= n; j++)
		{
			if(j == x || j == y) continue;
			f[x][j] = f[y][j] = 1ll * (f[x][j] + f[y][j]) % mod * inv % mod; 
			f[j][x] = f[j][y] = 1ll * (f[j][x] + f[j][y]) % mod * inv % mod; 
		}
	}
	for(int i = n; i >= 1; i--)
		for(int j = i - 1; j >= 1; j--)
			ans = (ans + f[j][i]) % mod; 
	printf("%lld\n", 1ll * ans * fpow(2, q) % mod); 
	return 0; 
}
posted @ 2020-04-28 20:12  ztlztl  阅读(98)  评论(0编辑  收藏  举报