首页 > 其他 > 详细

AGC030D 题解

时间:2021-02-05 23:27:09      阅读:31      评论:0      收藏:0      [点我收藏+]

题意简述

给定一个长度为 \(n\) 序列和 \(m\) 次操作,每次操作交换一对位置上的元素。

现在每一个操作可以做也可以不做,求所有操作方案得到的最终序列的逆序对个数和。

\(n,m\le 3000\)

算法分析

直接做没有头绪,考虑期望化。

期望有一个很重要的线性性质,可以将问题独立。我们考虑每一对逆序对的单元是一对数,因此我们需要维护所有二元组 \(\left(x,y\right)\) 满足 \(a_x<a_y\) 的概率。

这样对于一次交换操作的做或不做,只会影响到与当前操作相关的二元组,这些二元组要么包含第一个数,要么包含第二个数,总量为 \(O(n)\) ,可以接受。

注意最后将概率和乘上 \(2^m\)

总时间复杂度为 \(O(n^2+nm)\)

代码实现

#include<bits/stdc++.h>
using namespace std;
#define maxn 3005
#define maxm 2000005
#define inf 0x3f3f3f3f
#define int long long
#define mod 1000000007
#define local
void file(string s){freopen((s+".in").c_str(),"r",stdin);freopen((s+".out").c_str(),"w",stdout);}
template <typename Tp> void read(Tp &x){
	int fh=1;char c=getchar();x=0;
	while(c>‘9‘||c<‘0‘){if(c==‘-‘){fh=-1;}c=getchar();}
	while(c>=‘0‘&&c<=‘9‘){x=(x<<1)+(x<<3)+(c&15);c=getchar();}x*=fh;
}
int n,m;
int a[maxn];
int dp[maxn][maxn];
int ksm(int b,int p){int ret=1;while(p){if(p&1)ret=1ll*ret*b%mod;b=1ll*b*b%mod;p>>=1;}return ret;}
signed main(){
	read(n);read(m);
	for(int i=1;i<=n;++i)read(a[i]);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			dp[i][j]=(a[i]<a[j]);
		}
	}
	for(int i=1,x,y;i<=m;++i){
		read(x);read(y);
		dp[x][y]=dp[y][x]=1ll*ksm(2,mod-2)*(dp[x][y]+dp[y][x])%mod;//两者交换,等概率出现自身与对方的情况
		for(int j=1;j<=n;++j){
			if(j!=x&&j!=y){//下面两种同理
				dp[x][j]=dp[y][j]=1ll*ksm(2,mod-2)*(dp[x][j]+dp[y][j])%mod;
				dp[j][x]=dp[j][y]=1ll*ksm(2,mod-2)*(dp[j][x]+dp[j][y])%mod;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i){
		for(int j=1;j<i;++j){
			ans=(ans+dp[i][j])%mod;
		}
	}
	ans=1ll*ans*ksm(2,m)%mod;
	printf("%lld\n",ans);
	return 0;
}

AGC030D 题解

原文:https://www.cnblogs.com/ZigZagKmp/p/14380052.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!