AGC030D Inversion Sum题解

洛谷题意传送门

题意

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

\(n\le 3000,q\le 3000,A_i \le 10^9\)

题解

​ 因为 \(n\) 比较小,所以考虑确定逆序对i,j的答案。
​ 状态 \(dp[i][j]\) 表示 \(a[i]>a[j]\) 的方案数,随着 \(q\) 一个一个输入更新,但是不太行。

​ 考虑把状态改成期望,之后 \(\times2^q\) 即可。

​ 复杂度 \(O(n^2+n\times q)\)

代码

#include <bits/stdc++.h>
using namespace std ;
#define ll long long
#define rep(i,l,r) for(ll i=(l);i<=(r);++i)
#define per(i,r,l) for(ll i=(r);i>=(l);--i)
#define wif while
const ll inf = INT_MAX , df = 3005 , mod = 1e9 + 7 ;
ll i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,dp[df][df],a[df],ans ;
inline ll read()	{
	ll x = 0 , y = 1 ;	char ch = getchar() ;
	wif( ch > '9' || ch < '0' )		y = ( ch == '-' ) ? - 1 : 1 , ch = getchar() ;
	wif( ch >= '0' && ch <= '9' )	x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar() ;
	return x * y ;	}
int main()	{
	n = read() , q = read() ;	rep(i,1,n)	a[i] = read() ;
	rep(i,1,n)	rep(j,1,n)	dp[i][j] = ( a[i] > a[j] ) ;
	ll inv2 = (mod+1) / 2 , cur = 1 ;
	rep(i,1,q)	{
		cur *= 2 , cur %= mod ;
		ll x = read() , y = read() ;
		rep(j,1,n)	{
			if( j == x || j == y )	continue ;
			ll ty = ( dp[x][j] + dp[y][j] ) % mod * inv2 % mod , tx = ( dp[j][x] + dp[j][y] ) % mod * inv2 % mod ;
			dp[x][j] = dp[y][j] = ty ;
			dp[j][x] = dp[j][y] = tx ;
		}
		ll ty = dp[x][y] + dp[y][x] ;
		dp[x][y] = dp[y][x] = ty % mod * inv2 % mod ;	}
	rep(i,1,n-1)	{
		rep(j,i+1,n)	( ans += dp[i][j] ) %= mod ;
	}
	return printf("%lld\n",ans*cur%mod),0;
}
posted @ 2021-08-31 17:41  red_giant_bear  阅读(64)  评论(0)    收藏  举报