P5200 [USACO19JAN]Sleepy Cow Sorting G

题目描述

Farmer John正在尝试将他的 NN 头奶牛(1\le N\le 10^51≤N≤105),方便起见编号为 1\ldots N1…N,在她们前往牧草地吃早餐之前排好顺序。

当前,这些奶牛以 p_1,p_2,p_3,\ldots,p_Np1​,p2​,p3​,…,pN​ 的顺序排成一行,Farmer John站在奶牛 p_1p1​ 前面。他想要重新排列这些奶牛,使得她们的顺序变为 1,2,3,\ldots,N1,2,3,…,N,奶牛 11 在 Farmer John 旁边。

今天奶牛们有些困倦,所以任何时刻都只有直接面向 Farmer John 的奶牛会注意听 Farmer John 的指令。每一次他可以命令这头奶牛沿着队伍向后移动 kk 步,kk 可以是 11 到 N−1N−1 之间的任意数。她经过的 kk 头奶牛会向前移动,腾出空间使得她能够插入到队伍中这些奶牛之后的位置。

例如,假设 N=4N=4,奶牛们开始时是这样的顺序:

 FJ: 4 3 2 1

唯一注意 FJ 指令的奶牛是奶牛 44。当他命令她向队伍后移动 22 步之后,队伍的顺序会变成:

 FJ: 3 2 4 1 

现在唯一注意 FJ 指令的奶牛是奶牛 33,所以第二次他可以给奶牛 33 下命令,如此进行直到奶牛们排好了顺序。

Farmer John 急欲完成排序,这样他就可以回到他的农舍里享用他自己的早餐了。请帮助他求出一个操作序列,使得能够用最少的操作次数将奶牛们排好顺序。

输入格式

输入的第一行包含 NN。第二行包含 NN 个空格分隔的整数:p_1,p_2,p_3,\ldots,p_Np1​,p2​,p3​,…,pN​,表示奶牛们的起始顺序。

输出格式

输出的第一行包含一个整数 KK,为将奶牛们排好顺序所需的最小操作次数。

第二行包含 KK 个空格分隔的整数,c_1,c_2,\ldots,c_Kc1​,c2​,…,cK​,每个数均在 1\ldots N−11…N−1 之间。如果第 ii 次操作 FJ 命令面向他的奶牛向队伍后移动 c_ici​ 步,那么 KK 次操作过后奶牛们应该排好了顺序。

如果存在多种最优的操作序列,你的程序可以输出其中任何一种。

输入输出样例

输入 #1复制

4
1 2 4 3

输出 #1复制

3
2 2 3

思路:因为所有大的数都要往后去,变成递增序列

所以我们从后往前看,如果到达i这个位置的时候a[i]>a[i+1]

那么就说明i和i前面的所有数都需要往后移动

所以我们先从后往前找到一个突然递增的数a[i],那么他和他前面的数的数量就是需要操作几步

那么i后面的数就已经确定位置了

那么对于没有确定的数,他需要挪动的步数是:没有确定的数+已经确定但是比他小的数

(这步自己模拟样例就能找出来规律)

求已经确定但是比他小的数就用树状数组来求

那么先找到这个数的下标id

id+1~n都已经确定,那么add(a[i],1)

然后从1开始到id

不确定的数的数量就是id-i

确定但是比他小的数的个数就是sum(a[i]-1)

/*

 .----------------.  .----------------.  .----------------.  .----------------. 
| .--------------. || .--------------. || .--------------. || .--------------. |
| |  ________    | || |  _________   | || | ____    ____ | || |     ____     | |
| | |_   ___ `.  | || | |_   ___  |  | || ||_   \  /   _|| || |   .'    `.   | |
| |   | |   `. \ | || |   | |_  \_|  | || |  |   \/   |  | || |  /  .--.  \  | |
| |   | |    | | | || |   |  _|  _   | || |  | |\  /| |  | || |  | |    | |  | |
| |  _| |___.' / | || |  _| |___/ |  | || | _| |_\/_| |_ | || |  \  `--'  /  | |
| | |________.'  | || | |_________|  | || ||_____||_____|| || |   `.____.'   | |
| |              | || |              | || |              | || |              | |
| '--------------' || '--------------' || '--------------' || '--------------' |
 '----------------'  '----------------'  '----------------'  '----------------'

*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<cmath>
#include<stack>
#define int long long
#define lowbit(x) x&(-x)
#define PI 3.1415926535
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b) {
	return b? gcd(b,a%b):a;
}
/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/
//int e[N],ne[N],h[N],idx,w[N];
/*void add(int a,int b,int c){
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}
*/
const int N=1e5+10;
int n;
int a[N];
int tr[N*4];
vector<int> yy;
void add(int x,int c){
	for(int i=x;i<=n;i+=lowbit(i))tr[i]+=c;
}
int sum(int x){
	int res=0;
	for(int i=x;i;i-=lowbit(i))res+=tr[i];
	return res;
}
void sove(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	int id=0;
	for(int i=n-1;i>=1;i--){
		if(a[i]>a[i+1]){
			id=i;
			break;
		}
	}
	cout<<id<<endl;
//	cout<<"id=="<<id<<endl;
	if(id==0)return ;
	for(int i=id+1;i<=n;i++){
		add(a[i],1);
	//	cout<<"i=="<<i<<endl;
	}
	for(int i=1;i<=id;i++){
		int con=id-i+sum(a[i]-1);
		add(a[i],1);
		cout<<con<<" ";
	}
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie() ,cout.tie() ;
	int t=1;
//	cin>>t;
	while(t--){
		sove();
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值