题意:给定一个初始序列,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);
}
}```