Strange Sorting
题解
首先可以发现,是一定有解的。
我们在第一次移动后肯定可以使得
n
n
n在最后一个位置,第二次移动后一定可以使得
n
−
1
n-1
n−1在倒数第
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+1⩽ti⩽ti+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+1−1时序列的状况。我们记
[
i
,
n
]
[i,n]
[i,n]在
t
i
−
1
t_i-1
ti−1时刻的序列首位为
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+1−1时刻的序列形状我们也会是不可能维护出来的,但我们知道初始的序列形状啊。
初始序列显然是
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+1→fi+1,i,i+1→i,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;
}