2023ICPC网络预选赛 ( 2 ) (2) C.Covering【2-SAT、前后缀虚拟节点区间连边】

本文主要是介绍2023ICPC网络预选赛 ( 2 ) (2) C.Covering【2-SAT、前后缀虚拟节点区间连边】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C.Covering

1

题意

给定一个长度为 n n n 的正整数数组 a a a,现在要从中选择一些下标,满足:

  1. 对于每个下标 i i i i i i i − 1 i - 1 i1 至少 有一个被选
  2. 对于所有选择的下标,任意两个下标 i , j ( i ≠ j ) , a [ i ] ≠ a [ j ] 或 a [ i + 1 ] ≠ a [ j + 1 ] i,j(i \neq j),\hspace{4pt} a[i] \neq a[j] 或 a[i + 1] \neq a[j+1] i,j(i=j),a[i]=a[j]a[i+1]=a[j+1]
  3. 不能选择下标 n n n

分析可以发现:下标 1 1 1 一定要被选,因为它前面没有下标了,下标 n − 1 n - 1 n1 一定要被选,因为下标 n n n 不能选

考虑 2 − S A T 2-SAT 2SAT

  • 对于限制 1 1 1:连边 i ˉ → i − 1 \bar i \rarr i - 1 iˉi1 i ˉ → i + 1 \bar i \rarr i + 1 iˉi+1
  • 对于限制 2 2 2:连边 i → 集合 S i \rarr 集合 S i集合S,集合 S = ( j , ∀ j ≠ i , a [ j ] = a [ i ] ∧ a [ j + 1 ] = a [ i + 1 ] ) S = (j, \forall j \neq i, \hspace{3pt} a[j] = a[i] \wedge a[j + 1] = a[i + 1]) S=(j,j=i,a[j]=a[i]a[j+1]=a[i+1])
  • 由于 1 1 1 必选, n n n 必不选,因此可以连边: 1 ˉ → 1 \bar 1 \rarr 1 1ˉ1 n → n ˉ n \rarr \bar n nnˉ,用以确定是否存在可行解

如果对于限制 2 2 2 暴力连边,复杂度太高,考虑优化:

可以发现对于每种键值 ( a [ i ] , a [ i + 1 ] ) (a[i], a[i + 1]) (a[i],a[i+1]),它们要连的集合都是除了自己本身以外的拥有相同键值的所有点,这里会分割成一个前缀后缀

2
例如上图, A A A 值表示拥有这个键值的所有下标(前面下划线表示反变量) A 3 A_3 A3 需要连接 A ˉ 1 \bar A_1 Aˉ1 A ˉ 2 \bar A_2 Aˉ2,我们只需要将其连向 p r e 2 pre_2 pre2 A 3 → p r e 2 A_3 \rarr pre_2 A3pre2 就可以完成前缀的连边,同时 p r e 3 → A ˉ 3 pre_3 \rarr \bar A_3 pre3Aˉ3 p r e 3 → p r e 2 pre_3 \rarr pre_2 pre3pre2,以便后续相同键值的连边

后缀也是类似

需要注意的是:新建虚拟节点并不是严格按照正反变量的奇偶位置来排列的,而是紧挨着
所以我们判断可行解,只需要判断到 n n n 即可,否则会因为虚拟节点而干扰正确答案!

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n' 
#define ull unsigned long long
#define sz(x) (int)x.size()const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;typedef long long ll;struct TwoSat {int n; //属性数量std::vector<std::vector<int>> e;std::vector<bool> ans;TwoSat(int n) : n(n), e(2 * n), ans(n) {} //下标从0开始/* 建边表示 u为f 且 v为g */void addedge(int u, bool f, int v, bool g) { //原变量和反变量相邻放e[2 * u + !f].push_back(2 * v + g); //反变量在偶数位置,原变量在奇数位置e[2 * v + !g].push_back(2 * u + f);}bool satisfiable(int nn) {std::vector<int> id(2 * n, -1), dfn(2 * n, -1), low(2 * n, -1);std::vector<int> stk;int now = 0, cnt = 0;std::function<void(int)> tarjan = [&](int u) {stk.push_back(u);dfn[u] = low[u] = now++;for (auto v : e[u]) {if (dfn[v] == -1) {tarjan(v);low[u] = std::min(low[u], low[v]);} else if (id[v] == -1) {low[u] = std::min(low[u], dfn[v]);}}if (dfn[u] == low[u]) {int v;do {v = stk.back();stk.pop_back();id[v] = cnt;} while (v != u);++cnt;}};for (int i = 0; i < 2 * n; ++i) if (dfn[i] == -1) tarjan(i);for (int i = 0; i < nn; ++i) {if (id[2 * i] == id[2 * i + 1]) return false;ans[i] = id[2 * i] > id[2 * i + 1]; //取依赖性更高的那个}return true;}std::vector<bool> get_ans() { return ans; }
};const ll P = 1000001;
const int N = 200050;int yes(int x) {return 2 * x + 1;}
int no(int x) {return 2 * x;}int main(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);int n;std::cin >> n;std::vector<int> a(n);TwoSat ts(2 * n + 2);fore(i, 0, n)	std::cin >> a[i];int tot= 2 * n - 1;std::map<std::pair<int, int>, int> pre;std::map<std::pair<int, int>, int> suf;ts.e[0].push_back(1);ts.e[2 * n - 1].push_back(2 * n - 2);fore(i, 0, n){if(i > 0)	ts.addedge(i - 1, 1, i, 1);if(i < n - 1)	ts.addedge(i, 1, i + 1, 1);if(i < n - 1){if(pre.find({a[i], a[i + 1]}) != pre.end()){ts.e[2 * i + 1].push_back(pre[{a[i], a[i + 1]}]);ts.e[tot + 1].push_back(pre[{a[i], a[i + 1]}]);}pre[{a[i], a[i + 1]}] = ++tot;ts.e[tot].push_back(2 * i);}}for(int i = n - 2; i >= 0; --i){if(suf.find({a[i], a[i + 1]}) != suf.end()){ts.e[2 * i + 1].push_back(suf[{a[i], a[i + 1]}]);ts.e[tot + 1].push_back(suf[{a[i], a[i + 1]}]);}suf[{a[i], a[i + 1]}] = ++tot;ts.e[tot].push_back(2 * i);}if(!ts.satisfiable(n)){std::cout << "NO\n";return 0;}auto v = ts.get_ans();std::vector<int> ans;fore(i, 0, n - 1)if(v[i])ans.push_back(i + 1);std::cout << ans.size() << endl;for(auto i : ans)	std::cout << i << ' ';std::cout << endl;return 0; 
}/*
https://pintia.cn/problem-sets/1705510247604809728/exam/problems/1705514248467492866?type=7&page=0
*/

这篇关于2023ICPC网络预选赛 ( 2 ) (2) C.Covering【2-SAT、前后缀虚拟节点区间连边】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/891795

相关文章

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

Mysql虚拟列的使用场景

《Mysql虚拟列的使用场景》MySQL虚拟列是一种在查询时动态生成的特殊列,它不占用存储空间,可以提高查询效率和数据处理便利性,本文给大家介绍Mysql虚拟列的相关知识,感兴趣的朋友一起看看吧... 目录1. 介绍mysql虚拟列1.1 定义和作用1.2 虚拟列与普通列的区别2. MySQL虚拟列的类型2

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.