CF1907F
题意
给一个数组,可以将其进行两种操作:翻转,循环右移一位。求最小操作数使得它单调不减。
题面
好的样例创造好的题目,样例使我在打这题时思路特别的顺畅。
首先,发现两种操作都不会影响两个元素的相对位置(相邻的位置仍然相邻,相距
发现右移后翻转,等于翻转后的串左移。所以“右移
因此发现以下四种操作方案可能会最优:“翻转,右移
由于环形右移,所以使用常有的套路:将整个序列复制一遍接到后面。
如果发现接后的序列单调不升/不降的最长子串长度小于
如果发现大于
如果最长单调不降子串长度等于
具体地,对于每个位置
时间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int _;
int n;
int a[N],cnt1[N],cnt2[N],r1,r2;
int ans1,ans2;
void solve() {
scanf("%d",&n),r1=r2=0,ans1=ans2=N;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) a[i+n]=a[i];
for(int i=1;i<=2*n;i++) {
if(a[i]>a[i-1]) cnt1[i]=cnt1[i-1]+1,cnt2[i]=1;
if(a[i]<a[i-1]) cnt2[i]=cnt2[i-1]+1,cnt1[i]=1;
if(a[i]==a[i-1]) cnt1[i]=cnt1[i-1]+1,cnt2[i]=cnt2[i-1]+1;
r1=max(r1,cnt1[i]),r2=max(r2,cnt2[i]);
}
if(r1<n&&r2<n) return puts("-1"),void();
if(r1>n&&r2>n) return puts("0"),void();
if(r1==n) for(int i=n;i<=2*n;i++) if(cnt1[i]==n) ans1=min(ans1,min(2*n-i,i-n+2));
if(r2==n) for(int i=n;i<=2*n;i++) if(cnt2[i]==n) ans2=min(ans2,min(2*n-i,i-n)+1);
printf("%d\n",min(ans1,ans2));
return;
}
int main() {
scanf("%d",&_);
while(_--) solve();
return 0;
}