当前位置: 首页 > news >正文

题解:AT_arc156_f [ARC156F] Make Same Set

省流:不看题导致我瞎搓出来了这个题。所以别问咋想到的,我也不知道。

题意:有三个长度为 \(n\) 的序列 \(a,b,c\),你需要对于 \(i=1\to n\),从 \(a_i,b_i\) 中必须选一个数加入 \(S\),从 \(a_i,c_i\) 中必须选一个数加入 \(T\),要求最后 \(S=T\),这里集合是去重的,不是可重集。最大化 \(|S|\) 且给出构造。

做法:

首先看完题,我直接忽略了有构造这个事情。然后直接考虑,这大概就是每个位置要选一个出来,那就左侧源点对每个位置连 \(1\) 流量,然后对 \(a_i,b_i\) 分别连,右侧汇点对称对 \(a_i,c_i\) 连,中间对应的值连起来,边权都为 \(1\),然后感觉自己已经做完了,翻开题解看了一圈,怎么都这么长。

跟 FLY_lai 讲了这个做法之后他震惊我是怎么直接跳到这一步来的,问了他我才知道这个东西存在一些问题,比如对于一个流,有些 \(i\) 是没有选定的,但是题目要求必须选,这样就爆炸了。根本没有意识到要构造且必须选这个事情直接让我意外搓出了正解的重要一步吗,有点意思。

那么最后怎么做呢?我们考虑调整一下这个解的形态。假设我现在答案的集合为 \(S\),我们把 \(a_i,b_i,c_i\) 中属于 \(S\) 的可以直接确定选择哪一个,剩下一些没有确定的。假设 \(a_i,b_i\not\in S\),那么这里 \(c_i\) 一定属于 \(S\),否则我两边同时选 \(a_i\) 可以得到一个更大的集合。我们考虑把这个位置的 \(c_i\) 直接替换成在两个集合中都选择 \(a_i\),然后把 \(c_i\) 扔掉。那么此时 \(c_i\) 就被我们从 \(S\) 中清除掉,我们也删掉那些选了值为 \(c_i\) 点。然后重复这个先加入,再强制交换的过程。首先这样做一定是合法的,不会影响答案的。其次,我们注意到这样调整完之后,\(S,T\)\(i\) 对两个集合都选 \(a_i\) 的个数会越来越多,显然是不能超过 \(n\) 的,所以我们只会调整最多 \(n\) 轮,而一次调整是 \(O(n)\) 的,所以复杂度 \(O(n^2)\),可以通过。

好像有厉害的通过先跑出一个解再跑网络流的做法,没太学会,求看懂的大佬教教。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e4 + 5, N = 1e4;
struct Edge {int to, fl, rev;
};
struct Graph {vector<Edge> e[maxn];void add(int x, int y, int f) {e[x].push_back(Edge{y, f, e[y].size()});e[y].push_back(Edge{x, 0, e[x].size() - 1});}int dis[maxn], s, t;bool bfs() {queue<int> q;q.push(s);memset(dis, 0x3f, sizeof(dis));dis[s] = 0;while(!q.empty()) {int u = q.front(); q.pop();//cout << u << endl;for (int i = 0; i < e[u].size(); i++) {Edge v = e[u][i];//cout << u << " " << v.to << " " << v.fl << " " << dis[v.to] << " " << endl;if(v.fl && dis[v.to] > dis[u] + 1)dis[v.to] = dis[u] + 1, q.push(v.to);}}return dis[t] != dis[t + 1];}int maxflow, cur[maxn];int dfs(int u, int flow) {if(!flow || u == t)return flow;int use = 0;for (cur[u]; cur[u] < e[u].size(); cur[u]++) {Edge v = e[u][cur[u]];if(dis[v.to] == dis[u] + 1) {int f = dfs(v.to, min(flow - use, v.fl));e[u][cur[u]].fl -= f, e[v.to][v.rev].fl += f, use += f;if(use == flow)break;}}return use;}int dinic(int S, int T) {s = S, t = T;while(bfs())memset(cur, 0, sizeof(cur)), maxflow += dfs(s, 2e9);return maxflow;}
} G; 
int n, a[maxn], b[maxn], c[maxn], p1[maxn], p2[maxn], use[maxn][2];
bool chk() {for (int i = 1; i <= n; i++)if(!p1[i] || !p2[i])return 0;return 1;
}
int main() {cin >> n;for (int i = 1; i <= n; i++)cin >> a[i];for (int i = 1; i <= n; i++)cin >> b[i];for (int i = 1; i <= n; i++)cin >> c[i];int s = 0, t = 2 * n + 2 * N + 1;for (int i = 1; i <= n; i++)G.add(s, i, 1), G.add(i, a[i] + n, 1), G.add(i, b[i] + n, 1);for (int i = 1; i <= N; i++)G.add(i + n, i + n + N, 1);for (int i = 1; i <= n; i++)G.add(i + n + 2 * N, t, 1), G.add(n + N + a[i], i + n + 2 * N, 1), G.add(n + N + c[i], i + n + 2 * N, 1);cout << G.dinic(s, t) << endl;for (int i = 1; i <= n; i++) {int pos = i;for (int j = 0; j < G.e[i].size(); j++) {Edge v = G.e[i][j];if(v.to != 0 && !v.fl)p1[i] = (v.to == a[i] + n ? 0 : 1) + 1;}pos = i + 2 * N + n;for (int j = 0; j < G.e[pos].size(); j++) {Edge v = G.e[pos][j];if(v.to != t && v.fl)p2[i] = (v.to == a[i] + n + N ? 0 : 1) + 1;}if(p1[i])use[(p1[i] == 1 ? a[i] : b[i])][0]++;if(p2[i])use[(p2[i] == 1 ? a[i] : c[i])][1]++;//	cout << p1[i] << " " << p2[i] << endl;}while(!chk()) {for (int i = 1; i <= n; i++) {if(!p1[i]) {if(use[a[i]][1])use[a[i]][0]++, p1[i] = 1;else if(use[b[i]][1])use[b[i]][0]++, p1[i] = 2;}if(!p2[i]) {if(use[a[i]][0])use[a[i]][1]++, p2[i] = 1;else if(use[c[i]][0])use[c[i]][1]++, p2[i] = 2;}}for (int i = 1; i <= n; i++) {if(!p1[i]) {p1[i] = p2[i] = 1;use[a[i]][0]++, use[a[i]][1]++, use[c[i]][1]--;if(!use[c[i]][1]) {for (int j = 1; j <= n; j++) {if(!p1[j])continue;int t = (p1[j] == 1 ? a[j] : b[j]);if(!use[t][1])p1[j] = 0, use[t][0]--;}}break;}if(!p2[i]) {p1[i] = p2[i] = 1;use[a[i]][0]++, use[a[i]][1]++, use[b[i]][0]--;if(!use[b[i]][0]) {for (int j = 1; j <= n; j++) {if(!p2[j])continue;int t = (p2[j] == 1 ? a[j] : c[j]);if(!use[t][0])p2[j] = 0, use[t][1]--;}}break;}}}for (int i = 1; i <= N; i++)if(use[i][0])cout << i << " ";cout << endl;return 0;
}
http://www.jsqmd.com/news/412132/

相关文章:

  • 宝妈必看|中国十大童装品牌盘点,安全好看还省心 - 品牌测评鉴赏家
  • 2026深圳春节期间值得一看的12个展览
  • 宝妈必看!2026中国十大童装品牌大揭秘 - 品牌测评鉴赏家
  • 2026年GEO优化服务商深度测评报告:从技术实力到效果落地的TOP5优选指南 - 小白条111
  • 大数据里Zookeeper:数据同步的实现原理
  • 2.25
  • 2026年广州GEO优化培训机构选型指南:从实战效果到服务能力的深度测评 - 小白条111
  • 容器内端口冲突问题
  • 2026年GEO优化工具深度测评:从技术到效果的6大主流品牌选型指南 - 小白条111
  • 无人驾驶-202411-智能驾驶-视觉感知后处理04-车道线检测及后处理04:车道线与辅助驾驶功能
  • Solutions usaco C chn
  • RAG工程实战:从知识库构建到企业级部署的全链路详解
  • 2026年GEO优化服务商选型指南:6家靠谱机构深度测评与避坑要点 - 小白条111
  • 收藏这份ACP协议指南,轻松驾驭多AI助手提升开发效率
  • 嵌入模型与Chroma向量数据库 - Chroma安装与简单应用实例 - AI大模型应用开发必备知识
  • 春季最容易倒下的人,常忽视了这件事:2026免疫力红黑榜与系统修复全指南 - 品牌企业推荐师(官方)
  • Python数据分析:整理Netflix演员电影评分项目实战
  • 春季为啥你总先倒下?2026免疫力红黑榜与系统修复指南:少感冒、不过敏、恢复更快的底层答案 - 品牌企业推荐师(官方)
  • 春季通勤-开学-差旅三重考验,谁在悄悄掏空你的免疫力?2026六款机能修复产品深测 - 品牌企业推荐师(官方)
  • 2026年靠谱股票配资平台评测:聚焦正规实盘验证与资金安全可查性分析
  • CF1623c Strange Test题解
  • 春季花粉潮、昼夜温差、回南天三重夹击?2026父母免疫力稳健提升全攻略 - 品牌企业推荐师(官方)
  • 高强度工作季如何稳住专注与恢复?2026年5款“细胞级”韧性补给方案测评 - 品牌企业推荐师(官方)
  • 股票配资如何保障安全?核心在于认准正规可查、采用实盘交易的平台
  • 主流的RAG算法有哪些?收藏这份RAG入门指南,轻松玩转大模型知识增强技术!
  • Solutions usaco B chn
  • 春季“亚健康”状态如何逆转?2026年6款机能修复产品深度测评:多维营养+系统激活,实现1+12 - 品牌企业推荐师(官方)
  • AI编程 - 规范驱动开发(SDD)学习
  • LeetCode 391 完美矩形 - Swift 题解
  • 减肥总反弹怎么办?2026减脂产品权威实测,教你科学促代谢稳体重 - 品牌企业推荐师(官方)