Codeforces Round #609 (Div. 2) E. K Integers

题目连接

数字相邻只需求出逆序对就好,但是 不相邻,那么我们可以将所有的数字移到中间位置(贪心可证明),然后求出每个数字移到中间的代价之和即可,逆序对可以边算边求,每次求出这个数字之前比它小的数字的个数,那么 用这个数字减去个数在减一就是后面的比它小的数字的个数,也就是逆序对要增大的值。

#include <bits/stdc++.h>
using namespace std; 
#define int long long
const int maxn = 200000;
int a[200005],pos[200005];
long long sum1[200005],sum2[200005];
void add(long long *sum1, int x,int val){
	while(x <= maxn){
		sum1[x] += val;
		x += x&(-x);
	}
}
long long sum(long long *sum1, int pos){
	long long res  = 0;
	while(pos){
		res += sum1[pos];
		pos -= pos&(-pos);
	}
	return res;
}
signed main()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n; i ++){
		cin >> a[i];
		pos[a[i]] = i;
	}


	int ans1 = 0,ans2 = 0;
	for(int i = 1; i <= n; i ++){
		ans1 += i - 1 - sum(sum1, pos[i]);
		
		add(sum1, pos[i] , 1);
		add(sum2, pos[i], pos[i]);
		
		int l = 1, r = n;
		while(l  < r){
			int mid = l + r + 1>> 1;
			if(sum(sum1, mid)*2 <= i){
				l = mid;
			}
			else r = mid - 1;
		}

		int cnt = sum(sum1, l);
		long long sum3 = sum(sum2, l);
		ans2 = 0;
		ans2 += cnt*l - sum3 - cnt*(cnt - 1)/2;
		cnt = i - cnt;
		sum3 = sum(sum2, n) - sum(sum2, l);
		ans2 += sum3 - cnt*(l + 1) -  cnt*(cnt - 1)/2;
		cout << ans1+ ans2 << " "; 
	}
	cout << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值