[AGC014F]Strange Sorting

Strange Sorting

题解

首先可以发现,是一定有解的。
我们在第一次移动后肯定可以使得 n n n在最后一个位置,第二次移动后一定可以使得 n − 1 n-1 n1在倒数第 2 2 2个位置。我们每次操作肯定可以使得某些数回到它原本应该在的位置,所以是一定有解的。

根据上面的考虑,我们可以发现,我们不妨倒着来考虑,因为较小的数不会对较大数的相对顺序产生影响,也不会影响其是否能够移动。所以当我们 ( i , n ] (i,n] (i,n]的已经有序后, i i i在那里都不会产生影响。
那我们可以定义 t i t_i ti表示我们使得区间 [ i , n ] [i,n] [i,n]变得有序的最小操作次数。
显然, t i + 1 ⩽ t i ⩽ t i + 1 + 1 t_{i+1}\leqslant t_i\leqslant t_{i+1}+1 ti+1titi+1+1,但我怎么判断 t i t_i ti该取那一个呢?显然,根据 i i i t i + 1 t_{i+1} ti+1时刻的位置呗。
求出 i i i t i + 1 t_{i+1} ti+1时刻的位置,当然就需要知道 t i + 1 − 1 t_{i+1}-1 ti+11时序列的状况。我们记 [ i , n ] [i,n] [i,n] t i − 1 t_i-1 ti1时刻的序列首位为 f i f_i fi
那么显然,那个时刻 i , i + 1 , f i + 1 i,i+1,f_{i+1} i,i+1,fi+1的相对关系有 3 3 3种可能, i , f i + 1 , i + 1 i,f_{i+1},i+1 i,fi+1,i+1 f i + 1 , i , i + 1 f_{i+1},i,i+1 fi+1,i,i+1 f i + 1 , i + 1 , i f_{i+1},i+1,i fi+1,i+1,i
只有第二种可能会使得 t i = t i + 1 t_i=t_{i+1} ti=ti+1,但即使是 t i + 1 − 1 t_{i+1}-1 ti+11时刻的序列形状我们也会是不可能维护出来的,但我们知道初始的序列形状啊。
初始序列显然是 i , i + 1 , f i + 1 i,i+1,f_{i+1} i,i+1,fi+1的某个排列,我们发现这个排列无论怎么操作都会处于一种循环位移的状态,比如 i , i + 1 , f i + 1 → f i + 1 , i , i + 1 → i , i + 1 , f i + 1 i,i+1,f_{i+1}\rightarrow f_{i+1},i,i+1\rightarrow i,i+1,f_{i+1} i,i+1,fi+1fi+1,i,i+1i,i+1,fi+1
事实上,在 f i + 1 f_{i+1} fi+1处在首位时,能够使得 i i i f i + 1 f_{i+1} fi+1 i + 1 i+1 i+1之间的初始排序只有 3 3 3 f i + 1 , i , i + 1 f_{i+1},i,i+1 fi+1,i,i+1 i , i + 1 , f i + 1 i,i+1,f_{i+1} i,i+1,fi+1 i + 1 , f i + 1 , i i+1,f_{i+1},i i+1,fi+1,i
所以我们通过这三者的初始位置就可以进行转移了。

时间复杂度 O ( n ) O\left(n\right) O(n)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double Ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e5+7;
const int inv2=499122177;
const double jzm=0.999;
const int zero=2000;
const int n1=150;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-8;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,a[MAXN],pos[MAXN],f[MAXN],t[MAXN];
signed main(){
	read(n);for(int i=1;i<=n;i++)read(a[i]),pos[a[i]]=i;
	t[n]=0;f[n]=n;
	for(int i=n-1;i>0;i--){
		if(!t[i+1]){
			if(pos[i]<pos[f[i+1]])f[i]=i;
			else t[i]=1,f[i]=f[i+1];
		}
		else{
			if(pos[f[i+1]]<pos[i]&&pos[i]<pos[i+1])
				t[i]=t[i+1],f[i]=f[i+1];
			else if(pos[i]<pos[i+1]&&pos[i+1]<pos[f[i+1]])
				t[i]=t[i+1],f[i]=f[i+1];
			else if(pos[i+1]<pos[f[i+1]]&&pos[f[i+1]]<pos[i])
				t[i]=t[i+1],f[i]=f[i+1];
			else t[i]=t[i+1]+1,f[i]=i+1;
		}
	}
	printf("%d\n",t[1]);
	return 0;
}

谢谢!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值