2022赛前模测14 二分图排列

给出一个 1 到 n 的排列 a ,我们将每个数字看做一个点,如果存在 a[i]>a[j] 且 i<j ,则在 (i,j) 之间连一条边。
最终如果得到的图为二分图,那么我们称 a 为二分图排列。二分图排列很稀有,因此给你一些机会,你可以选择 a 中的一些数字,把他的值变为 a[i] 的相反数。
问能否通过这样的修改,使得 a 变为二分图排列?如果可以,请输出合法的修改方案,如果有多种方案,请输出字典序最小的。
对于100%的数据,1≤t≤2000,1≤n≤1e6,∑n≤1e6。

修改后不存在长为3的下降序列,否则会出现奇环。
a中元素两两不同,不存在长为3的下降序列⇔可以划分为2个上升序列。
考虑dp, f[i][1/0]表示考虑i->n这一段,一个上升序列最开头为±a[i],另一个序列开头的最大值。
f[i][0/1]可由f[i + 1][0/1], ±a[i + 1]四个数转移而来。
维护字典序最小的方案需要从前向后结合dp结果贪心,分别记录2个上升序列的最后一个数值b, c.
比较b, c, ±a[i], f[i][1/0]的大小关系判断是否能拼接。
代码如下:

#include <bits/stdc++.h>

using namespace std;

inline int read() {
   
	int x = 0, f = 0; char ch = getchar();
	while (!isdigit(ch)) f = ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}

const int N = 1e6 + 10; 
int n, a[N], f[N][2]; 

void work() {
   
	n = read(); 
	for (int i = 1; i <= n; ++i) a[i] = read(); 
	for
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值