题意:
给出如下排序长度为lenlenlen的数组代码:
for(int i=1;i<=len;i++)
for(int j=1;j<=len;j++)
if(a[i]<a[j]) swap(a[i],a[j]);
给出一个长nnn的数组aaa,求排序[1,k][1,k][1,k]区间的交换次数,k=1,2,....,ik=1,2,....,ik=1,2,....,i
Solution:
显然我们需要模拟一便这个排序,不妨直接写一个这个程序,输出。
发现排序长度为lenlenlen时,有如下性质,第iii次会把最大值交换到iii处,且在第一次之后,由于从从前往后交换,最大值目前位于i−1i-1i−1处,于是这一次发生的交换次数为[1,i−1][1,i-1][1,i−1]大于a[i]a[i]a[i]的数的种数,因为相等的元素不交换。这个是可以用树状数组维护的,但这样的时间复杂度是O(n2)O(n^2)O(n2)的,不妨考虑一下相邻两个前缀有什么关系,下面考虑两个前缀[1,i−1][1,i-1][1,i−1]和[1,i][1,i][1,i]的关系,并且叫第一次暴力处理时发生交换的位置为[p1,p2,...,pm][p_{1},p_{2},...,p_{m}][p1,p2,...,pm],最后的结果的pip_{i}pi的会到pi+1p_{i+1}pi+1去,pmp_{m}pm会到p1p_{1}p1去,暴力处理之后的每一次都是把最大值交换到iii就不发生交换了,不难发现[p1,p2,...,pm][p_{1},p_{2},...,p_{m}][p1,p2,...,pm]这些位置就是前缀最大值的变化点,于是发生变化一定在此处,即a[i]>max(a[1],a[2],...,a[i−1])a[i]>max(a[1],a[2],...,a[i-1])a[i]>max(a[1],a[2],...,a[i−1])时,这样比较复杂,不妨按照这样的思路,先考虑:
a[i]<max(a[1],a[2],...,a[i−1])a[i]<max(a[1],a[2],...,a[i-1])a[i]<max(a[1],a[2],...,a[i−1])时:
此时最大值已经在[1,i−1][1,i-1][1,i−1]被找出来了,所以我们只需要在最大值在i−1i-1i−1时把最大值移到iii即可,即
ans[i]=ans[i−1]+count(a[i]+1,n) ans[i]=ans[i-1]+count(a[i]+1,n) ans[i]=ans[i−1]+count(a[i]+1,n)
其中count(x,y)count(x,y)count(x,y)是[1,i−1][1,i-1][1,i−1]中有多少数是∈[x,y]\in[x,y]∈[x,y]的,这个可以用树状数组同时维护
当a[i]=max(a[1],a[2],...,a[i−1])a[i]=max(a[1],a[2],...,a[i-1])a[i]=max(a[1],a[2],...,a[i−1])时,最大值都不需要移到iii,于是:
ans[i]=ans[i−1] ans[i]=ans[i-1] ans[i]=ans[i−1]
最后再来考虑a[i]>max(a[1],a[2],...,a[i−1])a[i]>max(a[1],a[2],...,a[i-1])a[i]>max(a[1],a[2],...,a[i−1])时
由于[1,i−1][1,i-1][1,i−1]的最大值不为a[i]a[i]a[i],但是还是存在一个最大值,替a[i]a[i]a[i]完成了交换工作,只需要在第一次暴力处理的时候把a[i]a[i]a[i]交换到1,就完成了把最大值更新为a[i]a[i]a[i]的工作,又最大值此时要从i−1i-1i−1被交换到iii处,这两个工作需要2的交换次数。并且由于修改最大值,之前的最大值有多个的情况下互相不会计数,而现在他们都需要和现在的最大值计数了,并且最大值第二次出现的位置pos之后的区间[pos,i−1][pos,i-1][pos,i−1]每个数都要与新最大值交换,于是此时有
$$
ans[i]=ans[i-1]+f[max(1,i-1)]*(i-1-second[max(1,i-1)]+1)+2
$$
这个思维难度有点大。。
// #include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#include<queue>
#include<cmath>
#include<cstring>
#define endl '\n'
using namespace std;
using ll=long long;
const int N=100005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;
int a[N],tot[N];
ll n,ans[N],tree[N];
bool vis[N];
inline int lowbit(int x){return -x&x;}
void add(int x,int val)
{
if(vis[x]) return;
vis[x]=true;
while(x<=n)
{
tree[x]+=val;
x+=lowbit(x);
}
}
ll getsum(int x)
{
ll ret=0;
while(x)
{
ret+=tree[x];
x-=lowbit(x);
}
return ret;
}
int first[N],second[N];
ll query(int l,int r){return getsum(r)-getsum(l-1);}
void work()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
tree[i]=vis[i]=tot[i]=first[i]=second[i]=0;
}
int max1=a[1];
add(a[1],1); first[a[1]]=1;
for(int i=2;i<=n;i++)
{
if(a[i]==max1) ans[i]=ans[i-1];
else if(a[i]<max1) ans[i]=ans[i-1]+query(a[i]+1,n);
else ans[i]=ans[i-1]+(second[max1]!=0)*(i-second[max1])+2;
add(a[i],1); max1=max(max1,a[i]);
if(!first[a[i]]) first[a[i]]=i;
else if(!second[a[i]]) second[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
cout<<ans[i];
if(i<n) cout<<" ";
add(a[i],-1);
}
cout<<endl;
}
int main()
{
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--) work();
return 0;
}