AlenaNuna

导航

树状数组 || 线段树 || Luogu P5200 [USACO19JAN]Sleepy Cow Sorting

题面:P5200 [USACO19JAN]Sleepy Cow Sorting

题解:

最小操作次数(记为k)即为将序列倒着找第一个P[i]>P[i+1]的下标,然后将序列分成三部分:前缀部分(待转移部分),k,后缀部分(不需转移部分)。

用树状数组维护前缀部分每一个数挪到后缀部分所需的最小代价(即插到第一个小于它的数前)(这部分完全可以用线段树做)。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=(1e5)+50;
 7 ll P[maxn],N,k,t[maxn];
 8 inline void Add(ll x){
 9     for(;x<=N;x+=x&(-x))t[x]++;
10     return;
11 }
12 inline ll Sum(ll x){
13     ll sum=0;
14     for(;x>0;x-=x&(-x))sum+=t[x];
15     return sum;
16 }
17 int main(){
18     scanf("%lld",&N);
19     for(int i=1;i<=N;i++)scanf("%lld",&P[i]);
20     k=0;//若查询不到,k也应为0,所以先置为0 
21     for(int i=N-1;i>=1;i--)
22         if(P[i]>P[i+1]){k=i; break;}
23     printf("%lld\n",k);
24     if(k==0)return 0;
25     for(int i=k+1;i<=N;i++)Add(P[i]);
26     for(int i=1;i<=k;i++){
27         printf("%lld ",k-i+Sum(P[i]));
28         Add(P[i]);
29     }
30     return 0;
31 }

By:AlenaNuna

 

posted on 2019-03-06 22:11  AlenaNuna  阅读(370)  评论(0编辑  收藏  举报