Sleepy Cow Sorting
题目传送门
题目大意
给你一个长度为n的数组,每次只能移动最前面的那个数字到任意位置
求将数组按非递减排序需要的移动的最小次数和每次移动的距离
思路
可以将给定的数组分为两部分,分别为后半段顺序正确的部分,和前半段顺序不对的部分
所以需要改变的即为前半段的部分,即为最优解
每次移动的距离为在前半段乱序走过的路径和后半经过的路径,前半段可以自己求,后半段可以使用树状数组维护
即将后半段正序部分建立起点权为1的树
AC Code
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define endl '\n'
#define INF 0x3f3f3f3f
#define int long long
// #define TDS_ACM_LOCAL
const int N=1e5 +9;
int n;
int ans[N];
int a[N],bit[N]; //对应原数组和树状数组
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
bit[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求A[1 - i]的和
int res = 0;
while(i > 0){
res += bit[i];
i -= lowbit(i);
}
return res;
}
void solve(){
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
int idx=n;
for(int i=n; i>=2; i--){
if(a[i]<a[i-1]) break;
updata(a[i],1);
idx--;
}
updata(a[idx],1), idx--;
for(int i=1; i<=idx; i++){
updata(a[i],1);
ans[i]=idx-i+getsum(a[i]-1);
}
cout<<idx<<endl;
for(int i=1; i<=idx; i++) cout<<ans[i]<<" ";
cout<<endl;
return ;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
solve();
return 0;
}