赛时很长时间用在 F 上,终是没有过 pretest 2。
首先 i 对答案有贡献充要条件为交换后 ai=i 且 a1…i−1={1…i−1},于是枚举两类交换,记 posi 为 i 在原数组 a 中位置:
对于这两种情况,分别枚举每个 i,若满足条件,求出交换后的结果。这个结果是在初始序列结果上进行微调的,具体地:
综上,求问有什么问题,亦或是代码细节?感激不尽!
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int a[N],c[N];
vector<int> U;
void upd(int x,int v){
for(;x<N;x+=(x&-x))c[x]+=v,U.push_back(x);
}
int qry(int x){
int res=0;
for(;x;x-=(x&-x))res+=c[x];
return res;
}
int pos[N];
bool ok[N];
int oks[N],n;
int fir0(){
int l=1,r=n,t;
while(l<=r){
int mid=(l+r)>>1;
if(qry(mid)<mid)t=mid,r=mid-1;
else l=mid+1;
}
return t;
}
int tt[N];
int cnt[N];
signed main() {
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T; cin >> T;
while (T--) {
U.clear();
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i],pos[a[i]]=i,ok[i]=0,cnt[i]=0;
bool flg=1;
for(int i=2;i<=n;++i)flg&=(a[i]==i);
if(flg){
cout<<n-2<<'\n';
continue;
}
int res=0;
for(int i=1;i<=n;++i){
if(qry(i-1)==i-1){
ok[i]=1;
if(a[i]==i)++res;
}
if(qry(i-1)==i-2&&a[i]==i){
tt[i]=fir0();
int x=pos[tt[i]];
++cnt[tt[i]];
}
else tt[i]=-1;
upd(a[i],1);
oks[i]=oks[i-1]+ok[i];
}
int ans=0;
ok[n+1]=1;
for(int i=1;i<=n;++i){
if(a[i]==i||(!ok[i]&&!ok[i+1]))continue;
int res1=res+1;
res1+=cnt[i];
res1+=(a[i]==pos[i]&&ok[pos[i]]);
ans=max(ans,res1);
}
for(int x:U)c[x]=0;
U.clear();
for(int i=1;i<=n;++i){
if(tt[i]!=-1){
int fr=tt[i],to=pos[fr];
int res1=res+1+cnt[fr]+(a[fr]==pos[to]&&ok[to]);
ans=max(ans,res1);
}
upd(a[i],1);
}
cout<<ans<<'\n';
for(int x:U)c[x]=0;
}
return 0;
}
(不算讨论区题解罢,毕竟连题解都算不上)