AGC052D Equal LIS【结论】

给定长为 \(n\) 的排列,求是否可以分割成两个 LIS 长度相等的子序列。

\(\sum n\le 2\cdot 10^5\)


\(f_i\) 是以 \(i\) 为结尾的 LIS 长度,\(L=\max_{i=1}^nf_i\) 是整体 LIS 长度。

\(2\mid L\) 时一定有解,划分为 \(f_i\le\frac L2\)\(f_i>\frac L2\) 两部分即可。

\(L=2k+1\) 为奇数时,两个子序列的 LIS 长度至少是 \(k+1\),所以必定存在某个 LIS 之外的元素,存在某个长为 \(k+1\) 的 IS 覆盖它。

事实证明这是充分的所以做完了,考虑构造:设这个长为 \(k+1\) 的 IS 的位置序列是 \(p_1,\cdots,p_{k+1}\),将满足 \(\forall j\in[1,k+1],f_i\ne f_{p_j}\)\(f_i=f_x\)\(i\ne x\)\(i\) 划分为第一个序列,其他的划分为第二个序列。

显然两个序列分别至多有 \(k+1\) 个不同的 \(f\),所以 LIS 长度 \(\le k+1\)

在第一个序列中,对于长为 \(L\) 的 LIS,其中恰有 \(k\) 个值不能选,所以 LIS 长度 \(\ge k+1\)

在第二个序列中,\(p\) 是其子序列,所以 LIS 长度 \(\ge k+1\)

所以再求出 \(g_i\) 表示以 \(i\) 为开头的 LIS 长度即可,时间复杂度 \(O(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
const int N = 200003;
template<typename T>
void read(T &x){
	int ch = getchar(); x = 0;
	for(;ch < '0' || ch > '9';ch = getchar());
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
int T, n, p[N], tr[N], f[N], g[N];
void upd(int p, int v){for(;p <= n;p += p & -p) chmax(tr[p], v);}
int qry(int p){int r = 0; for(;p;p -= p & -p) chmax(r, tr[p]); return r;}
void solve(){
	read(n); int ans = 0;
	memset(tr, 0, n+1<<2);
	for(int i = 1;i <= n;++ i){
		read(p[i]);
		upd(p[i], f[i] = qry(p[i]-1) + 1);
		chmax(ans, f[i]);
	}
	if(!(ans & 1)){puts("YES"); return;}
	memset(tr, 0, n+1<<2);
	for(int i = n, j = ans;i;-- i){
		upd(n+1-p[i], g[i] = qry(n-p[i]) + 1);
		if(f[i] == j) -- j;
		else if(f[i] + g[i] > (ans>>1) + 1){
			puts("YES"); return;
		}
	}
	puts("NO");
}
int main(){read(T); while(T --) solve();}
posted @ 2021-06-02 20:27  mizu164  阅读(127)  评论(0编辑  收藏  举报