题解:P14062 【MX-X21-T7】[IAMOI R5] 若我不曾见过太阳
若我不曾见过太阳题解
update:感谢 @Xiaohaoyu1020 指出本题解对于单调栈维护的错误。
这是一篇知更鸟推人的题解。
因为知更鸟,所以切了这道题,我的博客还有知更鸟赛的其他题解,欢迎来玩!
是一道思维好题呢。
首先,我们读懂题意后,通过手模样例发现排序与同剩余系相邻数之间的距离有关。
具体的说:对于下标为
发现到这里,我们距离答案就不远了,考虑交换两个数的意义是将一对逆序对恢复正序,考虑枚举分界点进行 0/1 染色。
对于分界点
由于是顺序枚举分界点,每次只会修改一个数是 0 或者 1 且最近逆序对的左右端都是单调移动的,所以考虑单调栈维护即可。
最后,知更鸟可爱捏~
代码:
#include<bits/stdc++.h>
#define Robin 0
using namespace std;
const int N=4e6+10;
int st[N],top;
int a[N];
int len[N];
int n;
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
top=0;
int ans=INT_MAX;
for(int i=1;i<=n;i++)
{
st[++top]=i;
while(top && a[st[top]]<=i) top--;
if(top) len[i]=st[top];
else len[i]=0;
}
top=0;
for(int i=n;i>=1;i--)
{
while(top && a[st[top]]>i) top--;
if(top) len[i]=st[top]-len[i];
if(len[i]>0) ans=min(ans,len[i]);
st[++top]=i;
}
if(ans==INT_MAX) cout<<"0\n";
else cout<<n-ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
// freopen("text.in","r",stdin);
// freopen("text.out","w",stdout);
int T;
cin>>T;
while(T--) solve();
return Robin;
}