ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1620F 题解

2021-12-21 10:03:26  阅读:143  来源: 互联网

标签:CF1620F int 题解 rep ans sgn 奇环 nw


CF1620F 题解

题意

给定排列 \(p\),要求拟定一个新序列 \(p'\),满足:

  1. \(\forall i \in [1,n],p'_i=\pm p_i\);
  2. 构造无向图 \(G\),其中 \((i,j)\) 有边当且仅当 \(i<j,p'_i>p'_j\),要求 \(G\) 是二分图。

请给出方案或报告没有方案。

做法

首先注意到,一张图不是二分图,当且仅当其存在至少一个奇环,

故考虑什么情况图中存在奇环。

直接想似乎没什么思路,我们考虑这种特殊图的一个性质,即:

若图中存在奇环,当且仅当图中存在一个长为 \(3\) 的奇环。

怎么证明?我们考虑反证法,但我们先要说明一些东西。

虽然题意是无向图,但我们在接下来考虑问题的时候,可以将边定向,即:

若 \(i<j\) 且 \(p'_i>p'_j\),则连一条 \(i\rightarrow j\) 的有向边。

我们先考虑三个点 \(i,j,k\),若同时存在两条有向边 \(i\rightarrow j,j\rightarrow k\),则等价于:

\(i<j<k,p'_i>p'_j>p'_k\),则图中也存在一条 \(i\rightarrow k\) 的有向边。

那么,我们开始反证,即若图中存在一个长度大于 \(3\) 的奇环但不存在长度为 \(3\) 的奇环,

那此时在奇环中,连接任意一点的两条边,

两条边要么同时是这个点的出边,要么同时是这个点的入边。

这样的话,任意点 \(u\) 的出度减入度之差 \(d_u\) 不是 \(2\) 就是 \(-2\),

则一个奇环上所有点的 \(d\) 值之和必然不为零,因为有奇数个点,

而实际上一个奇环上的点的 \(d\) 值之和显然必须为零,故产生矛盾。

故我们让图中不存在长为 \(3\) 的奇环,就可以满足条件。

而一张图中不存在长为 \(3\) 的奇环,当且仅当原序列 \(p'\) 中不存在 \(i<j<k\) 且 \(p'_i>p'_j>p'_k\)。

此时,我们考虑一个简单的 DP,即:

\(f_{i,x,y}\) 为填了序列 \(p'\) 的前 \(i\) 个,此时序列所有数最大为 \(x\),所有逆序对末尾数最大为 \(y\),

这样能否不存在长为 \(3\) 的奇环,若能则 \(f_{i,x,y}=1\),否则 \(f_{i,x,y}=0\)。

这样是 \(O(n^3)\) 的,显然过不去,而转移已经是 \(O(1)\) 的,无法优化,故我们考虑优化状态。

我们发现,对于两个都已经构造前了 \(i\) 位的序列 \(p1,p2\),若两者前 \(i\) 位的最大数都为 \(x\),

设两者的逆序对末尾数最大值分别为 \(y1,y2\),显然,在 \(y1\) 和 \(y2\) 中取小者对应的序列更有潜力,

或者,形式化的:不妨设 \(y1>y2\),则任意一个长为 \(n\) 的合法序列,

若其长为 \(i\) 的前缀由 \(p1\) 构成,则我们将前缀换成 \(p2\) 后也一定合法。

同样的,对于一对固定的 \((i,y)\),显然 \(x\) 越小序列越容易合法,就不过多赘述了。

那么,对于状态中一对固定的 \((i,x)\),我们只需要存储一个最小的可能 \(y\) 即可,即 \(f_{i,x}=y\)。

当然,如果对于状态中一对固定的 \((i,x)\),其不存在任何一个可能的 \(y\),我们就令 \(f_{i,x}=INF\)。

于是我们就将复杂度优化到了 \(O(n^2)\),但还是过不去。

看上去似乎这个无法再进一步优化状态,我们尝试写下状态转移方程:

设 \(z=\pm p_{i+1},f_{i,x}=y(z\geq y)\),则我们有:

  1. \(z<x\rightarrow f_{i+1,x}=z\);
  2. \(z\ge x\rightarrow f_{i+1,z}=y\)。

我们惊讶地发现,转移后新的 \((x,y)\) 中至少有一个值等于 \(z=\pm p_{i+1}\)。

那么,我们就只需要记 \(f_{i,0/1,0/1}\) 代表前 \(i\) 位,第 \(i\) 位填的值是正/负,其中 \(x/y\) 等于 \(\pm p_{i+1}\)。

状态的转移和前面本质相同,我就不写了,不会可以看代码。

这样的复杂度就是 \(O(n)\) 的了,也足以通过本题。

注意题中要求给出方案,故我们需要记录前驱。

code

#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)

using namespace std;
const int N (1e6 + 10);

vector < int > ans;
int n, p[N], f[N][2][2];
struct Node { int i, j, k; } pre[N][2][2];

void work() {
	cin >> n;
	rep (i, 1, n) cin >> p[i];
	rep (i, 0, n + 1) rep (j, 0, 1) 
	  rep (k, 0, 1) f[i][j][k] = 2e9;
	f[1][0][0] = f[1][1][0] = -2e9;
	rep (i, 1, n - 1) rep (j, 0, 1) rep (k, 0, 1) {
		int x, y, t = f[i][j][k];
		if (!j && !k) x = -p[i], y = t;
		if (!j && k)  x = t, y = -p[i];
		if (j && !k)   x = p[i], y = t;
		if (j && k)    x = t, y = p[i];
		Node nw = (Node) {i, j, k};
		rep (sgn, 0, 1) {
			int z = (sgn ? 1 : -1) * p[i + 1];
			if (z < y) continue;
			if (z < x) if (f[i + 1][sgn][1] > x) 
			  f[i + 1][sgn][1] = x, pre[i + 1][sgn][1] = nw;
			if (z >= x) if (f[i + 1][sgn][0] > y) 
			  f[i + 1][sgn][0] = y, pre[i + 1][sgn][0] = nw;
		}
	}
	rep (fj, 0, 1) rep (fk, 0, 1) {
		int i = n, j = fj, k = fk;
		if (f[i][j][k] < 2e9) {
			ans.clear(), puts ("YES");
			while (i >= 1) {
				ans.push_back (j ? p[i] : -p[i]);
				Node nw = pre[i][j][k];
				i = nw.i, j = nw.j, k = nw.k;
			}
			reverse (ans.begin(), ans.end());
			for (int x : ans) printf ("%d ", x);
			return puts (""), void();
		}
	}
	puts ("NO");
}

int main() {
	int tasks; cin >> tasks;
	while (tasks--) work();
	return 0;
}

标签:CF1620F,int,题解,rep,ans,sgn,奇环,nw
来源: https://www.cnblogs.com/GaryH/p/15714054.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有