CF1905F Field Should Not Be Empty 题解

特判如果排列初始时是 1,2,,n1,2,\cdots,n,输出 n2n-2

如果不是,那么我们交换两个后的结果一定大于等于初始值。

考虑新增的贡献是什么?假设交换 pi,pj(i<j)p_i,p_j(i < j),那么新增的贡献必然是一个 k[i,j]k \in [i,j],交换前 kk 不是好的,交换后是好的。

注意到位置 ii 是好的的必要条件是 pi=ip_i=i

考虑枚举上文的 kk。接着考虑交换的 i,ji,j 会怎么样。

第一种可能是,i=ki=kj=kj=k。那么根据必要条件,我们知道换的一定是 iipip_i 这两个位置。

第二种,iki \neq kjkj \neq k,那么交换的必然是 [1,i)[1,i) 中的最大值点和 (i,n](i,n] 中的最小值点,证明显然。

然后现在有 O(n)O(n)(i,j)(i,j),每一对算贡献都可以讨论贡献然后前缀和做到 O(1)O(1)。预处理有个 O(nlogn)O(n \log n) 的复杂度,但是可能可以优化?但是我们避开了树状数组或线段树等数据结构!

#pragma GCC optimize("-Ofast,fast-math,-inline")
#pragma GCC target("avx,sse,sse2,sse3,popcnt")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <vector>
using namespace std;

const int N = 2e5 + 5;

int t, n, p[N];
int minn[N], maxn[N];
bool g[N], f[N];
int sf[N], sg[N];
int ra[N];

inline int query(int l, int r)
{
	if (l > r) swap(l, r);
	int nl = l + 1, nr = r - 1;
	nl = max(nl, p[r] + 1);
	nr = min(nr, p[l] - 1);
	int res = 0;
	if (nl <= nr)
	{
		res += sg[nr] - sg[nl - 1];
	}
	res -= (sf[r - 1] - sf[l]);
	res -= f[l];
	res -= f[r];
	res += (p[l] == r && (maxn[r - 1] == r) && (p[r] <= r - 1));
	res += (p[r] == l && maxn[l - 1] == l - 1);
	return res;
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> t;
	while (t--)
	{
		int sum = 0;
		cin >> n;
		for (int i = 1; i <= n; i++) cin >> p[i], g[i] = f[i] = 0, ra[p[i]] = i;
		maxn[1] = p[1];
		for (int i = 2; i <= n; i++) maxn[i] = max(maxn[i - 1], p[i]);
		minn[n + 1] = (int)1e9;
		for (int i = n; i >= 1; i--) minn[i] = min(minn[i + 1], p[i]);
		if (is_sorted(p + 1, p + n + 1))
		{
			cout << n - 2 << "\n";
			continue;
		}
		set<int> s1;
		for (int i = 1; i <= n; i++)
		{
			f[i] = (p[i] == i) && (maxn[i - 1] == i - 1);
			g[i] = (p[i] == i) && (!s1.empty()) && (s1.upper_bound(p[i]) == --s1.end());
			s1.insert(p[i]);
			sum += f[i];
			sf[i] = sf[i - 1] + f[i];
			sg[i] = sg[i - 1] + g[i];
		}
		int ans = sum;
		for (int i = 1; i <= n; i++)
		{
			if (g[i])
			{
				ans = max(ans, sum + query(ra[maxn[i - 1]], ra[minn[i + 1]]));
			}
			if (p[i] != i) ans = max(ans, sum + query(i, p[i]));
		}
		cout << ans << "\n";
	}
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示