求问 CF F题
  • 板块学术版
  • 楼主cowardTester
  • 当前回复1
  • 已保存回复1
  • 发布时间2023/12/17 01:14
  • 上次更新2023/12/17 10:22:01
查看原帖
求问 CF F题
711690
cowardTester楼主2023/12/17 01:14

赛时很长时间用在 F 上,终是没有过 pretest 2。

首先 ii 对答案有贡献充要条件为交换后 ai=ia_i=i 且 a1…i−1={1…i−1}a_{1\dots i-1}=\{1\dots i-1\},于是枚举两类交换,记 posipos_i 为 ii 在原数组 aa 中位置:

  1. {a1…i−1}=1…i−1\{a_{1\dots i-1}\}={1\dots i-1} 且 ai≠ia_i\neq i,交换 aia_i 和 aposia_{pos_i};
  2. ai=ia_i=i 且 a1…i−1a_{1\dots i-1} 中有且仅有一位 pp,满足 ap>i−1a_p>i-1,交换 apa_p 和 apospa_{pos_p}。

对于这两种情况,分别枚举每个 ii,若满足条件,求出交换后的结果。这个结果是在初始序列结果上进行微调的,具体地:

  • 首先 +1+1,这次操作将 ii 从不好的变为好的;
  • 其次,设这次操作交换下标为 frfr 和 toto,其中 frfr 为上文 i/pi/p,考虑这次操作对 t=posi/pt=pos_{i/p} 的影响,即 a1…t−1={1…t−1}a_{1\dots t-1}=\{1\dots t-1\} 且 afr=postoa_{fr}=pos_{to};
  • 最后,考虑对于 i∈[min⁡{fr,to}+1,max⁡{fr,to}−1]i\in [\min\{fr,to\}+1,\max\{fr,to\}-1],是否对 ii 是否会对答案贡献产生影响,设这个值为 cntfrcnt_{fr},这个值可以在预处理中计算,具体地,正序枚举 ii,若 ii 离满足条件只需要在 a1…i−1a_{1\dots i-1} 中有一位与其余位交换,则计算这一位被交换过来的贡献。

综上,求问有什么问题,亦或是代码细节?感激不尽!

#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;
}

(不算讨论区题解罢,毕竟连题解都算不上)

2023/12/17 01:14
加载中...