题意:给定一个排列 ,每次能让队头移动到后面任意的位置,问最后需要多少步可以变成升序排列。
思路:看到了一个很妙的思路,我们从末尾开始往前面扫如果遇到不是降序的那么它以及它前面的元素都需要往后移动,所以第一个答案就确定了。第二问要输出方案,我们仔细观察,每一头牛需要往后的距离=他后面还没有排队好的牛和已经排队好比他小的牛。如果暴力应该是n^2的,这时候我们想想在查询排队好比他小的牛的时候能不能拿数据结构优化一下,想到了树状数组,因为该题目里只有单点修改和查询区间,那么就好办了。
代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N=100010;
int n;
int tr[N];
int lowbit(int x)
{
return x&-x;
}
void add(int x)
{
for(int i=x;i<=n;i+=lowbit(i))
tr[i]++;
}
int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=tr[i];
return res;
}
int a[N];
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
}
int k=0;
for(int i=n-1;i>=1;i--)
if(a[i]>a[i+1])
{
k=i;
break;
}
cout<<k<<endl;
for(int i=n;i>k;i--)
add(a[i]);
int ck=k;
int ct=1;
while(ck--)
{
cout<<(k-1)+query(a[ct++])<<' ';
add(a[ct-1]);
k--;
}
cout<<endl;
return 0;
}