题意:给N(1e5)个数的一个全排列,每次可以交换相邻的数,问最小交换次数达到数组满足a[i+1] = (a[i]%n)+1。
思路:假如换成1,2,3...n的排列,显然答案就是逆序数,那么加如1最终在位置2,留意到逆序数的变化与数字5的位置有关,因为数字5要最终去位置1了,所以枚举1的最终位置,过程O(1)维护逆序数。
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+30;
int n, id[maxn], sum[maxn];
void add(int x){
for(;x<=n;x+=x&-x) ++sum[x];
}
int query(int x){
int res = 0;
for(;x>0;x-=x&-x) res += sum[x];
return res;
}
int main(){
int T, x;
for(scanf("%d",&T);T;--T){
scanf("%d",&n);
for(int i=1; i<=n; ++i){
scanf("%d",&x);
id[x] = i;
sum[i] = 0;
}
LL tot = 0, ans;
for(int i=n; i>0; --i){
tot += query(id[i]);
add(id[i]);
}
ans = tot;
for(int i=n; i>1; --i){
tot -= n-id[i];
tot += id[i]-1;
ans = min(ans, tot);
}
printf("%lld\n",ans);
}
return 0;
}
本文探讨了一种算法问题,即给定N个数的全排列,通过最少的相邻数交换,使数组满足特定条件。文章提供了逆序数概念的解析,并通过枚举和维护逆序数的方法,实现了O(N log N)的高效求解。
2136

被折叠的 条评论
为什么被折叠?



