AT4513 [AGC030D] Inversion Sum

https://www.luogu.com.cn/problem/AT4513

像这种一个操作做或不做,总方案数特别大,求所有方案数满足什么条件的可以往概率方面想

交换与否的概率是等价的,所以可以先做一个概率DP
f [ i ] [ j ] 表 示 做 到 目 前 这 个 操 作 , a [ i ] > a [ j ] 的 概 率 f[i][j]表示做到目前这个操作,a[i]>a[j]的概率 f[i][j]表示做到目前这个操作,a[i]>a[j]的概率
最后求和再乘上 2 Q \large 2^Q 2Q就是答案了
转移也十分显然,每次操作 x , y x, y x,y,只有当 i , j i,j i,j其中一个为 x , y x,y x,y的其中一个的 D P DP DP值才会受影响,所以直接转移就好了
看代码理解一下吧
code:

#include<bits/stdc++.h>
#define mod 1000000007
#define N 3005
#define ll long long
using namespace std;
const int inv = (mod + 1) / 2;
int n, q, a[N];
ll f[N][N], g[N][N];
int main() {
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	for(int i = 1; i <= n; i ++)
	 	for(int j = 1; j <= n; j ++)
	 		f[i][j] = a[i] > a[j];
	ll ha = 1;
	while(q --) {
		
		int x, y;
		scanf("%d%d", &x, &y);
		if(x > y) swap(x, y);
		for(int i = 1; i <= n; i ++) if(i != x && i != y) {//转移
			g[i][x] = (ll) inv * (f[i][x] + f[i][y]) % mod;
			g[i][y] = (ll) inv * (f[i][x] + f[i][y]) % mod;
			g[x][i] = (ll) inv * (f[x][i] + f[y][i]) % mod;
			g[y][i] = (ll) inv * (f[x][i] + f[y][i]) % mod;
		}
//		for(int i = 1; i <= n; i ++) {
//			for(int j = 1; j <= n; j ++) printf("%lld ", f[i][j]); printf("\n");
//		} printf("\n");
		for(int i = 1; i <= n; i ++) if(i != x && i != y) {
			f[i][x] = g[i][x]; 
			f[i][y] = g[i][y];
			f[x][i] = g[x][i];
			f[y][i] = g[y][i];
		}
		f[x][y] = f[y][x] = (ll) inv * (f[x][y] + f[y][x]) % mod;//记得要考虑这种情况
		ha = ha * 2 % mod;
	}
	ll ans = 0;
	for(int i = 1; i <= n; i ++)
		for(int j = i + 1; j <= n; j ++)
			ans = (ans + f[i][j]) % mod;
	printf("%lld", ans * ha % mod);
	return 0;
}

思维还是要打开一点,这种题做了好多次了,要多思考
记得计数可以往概率方面想

上一篇:P5431 【模板】乘法逆元2(小学数学题,毒瘤鱼,卡常之王yyds)


下一篇:【转】LS和MMSE的区别