Codeforces Round #609 (Div. 1) C. K Integers(树状数组+二分+思维)

在这里插入图片描述
题意:给定一个初始序列,f(k)为把原序列的一个字串变成1,2,,,k所执行的最小操作,每次操作只能再相邻两个位置进行交换。
思路:很容易发现当1~k都是相邻的时候答案为逆序对,如果1-k不相邻的话怎么才能时操作最小呢,只需要把他们全都变成相邻的即可,具体看代码。

#include <bits/stdc++.h>
typedef long long ll;
const int maxn=2e5+1;
#define lowbit(i)  ((i)&(-i))
using namespace std;
ll n,cnt,ni,sum1[maxn],sum2[maxn],pos[maxn],num,t;
void add1(int x)
{
	while(x<=n) sum1[x]++,x+=lowbit(x);
}
void add2(int x,int v)
{
	while(x<=n) sum2[x]+=v,x+=lowbit(x); 
}
ll query1(int x)//查询的是x之前的比x小的个数 
{
	ll res=0; 
	while(x) res+=sum1[x],x-=lowbit(x);
	return res;
}
ll query2(int x)//查询的是x之前的下标之和 
{
	ll res=0;
	while(x) res+=sum2[x],x-=lowbit(x);
	return res;
}
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;++i) scanf("%lld",&t),pos[t]=i;
	for(int i=1;i<=n;++i)
	{
		ni+=i-1-query1(pos[i]);
		add1(pos[i]);add2(pos[i],pos[i]);
		int mid,l=1,r=n;
		while(l<=r)
		{
			mid=(l+r)>>1;
			if(query1(mid)*2<=i) l=mid+1;
			else r=mid-1;
		}
		ll ans=0;
		cnt=query1(l),num=query2(l);
		ans+=l*cnt-num-cnt*(cnt-1)/2;
		cnt=i-cnt;num=query2(n)-num;
		ans+=num-cnt*(l+1)-cnt*(cnt-1)/2;
		printf("%lld ",ni+ans);
	}
}```

发布了39 篇原创文章 · 获赞 0 · 访问量 1095

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/103899419