Codeforces Round #301 (Div. 2) E

Infinite Inversions

        一个无穷的数列1,2,3......进行n(n<=100000)次swap操作,问操作后的数列有多少逆序对。

        考虑到交换的数可能比较大,但是交换的次数相对少,可以用离散化解决。离散化以后,模拟一下操作。然后逆序对可以分为两部分考虑,一部分是被交换了的数之间的逆序对,另一部分是被交换的数与没交换的数之间的逆序对。在这个数列中,每个数是唯一的,用离散化后的值借助树状数组可以得出被交换了的数之间的逆序对(就是经典的逆序对求法)。除了用map存每个被交换的数的“名次”外,我们再开一个数组,根据“名次”可以找到相应的数,这样就可以利用名次计算出被交换的数与没交换的数之间的逆序对。具体见代码。

        感觉自己实力有所增强了,div2的场基本上都能出D,E也能赛后不借助外力A掉。


#include <bits/stdc++.h>  
using namespace std; 

#define ll long long
const int maxn=100010;


int a[maxn];
int b[maxn];
int c[maxn*2];
int _mp[maxn*2];

int cnt;
int cc[maxn*2];
int lowbit(int x){
	return x&(-x);
}

void update(int pos){
	while(pos<=cnt){
		cc[pos]++;
		pos+=lowbit(pos);
	}
}

int query(int pos){
	int re=0;
	while(pos){
		re+=cc[pos];
		pos-=lowbit(pos);
	}
	return re;
}

int main(){
	int n;
	cin>>n;
	map<int,int> mp;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i],&b[i]);
		mp[a[i]]=1;
		mp[b[i]]=1;
	}
	
	cnt=0;
	for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
		it->second=++cnt;
		_mp[cnt]=it->first;
	}
	
	ll ans=0;
	for(int i=1;i<=cnt;i++){
		c[i]=i;
	}
	for(int i=1;i<=n;i++){
		swap(c[ mp[a[i]] ],c[ mp[b[i]] ]);
	}

	for(int i=1;i<=cnt;i++){
		ans+=c[i]-1-query(c[i]-1);
		
		//当前数 
		int num=_mp[ c[i] ];
		//交换前数 
		int ori=_mp[ i ]; 
		//前面未被交换的数中有tmp1个大于当前数 
		int tmp1=ori-num-(mp[ori]-mp[num]);
		//后面未被交换的数中有tmp2个小于当前数 
		int tmp2=num-ori-(mp[num]-mp[ori]);
		if( tmp1>0 ){
			ans+=tmp1;
		}
		if( tmp2>0 ){
			ans+=tmp2;
		}
		update(c[i]);
	}
	
	cout<<ans<<endl;
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值