题目链接

https://atcoder.jp/contests/agc038/tasks/agc038_f

题解

好题。
首先观察到一个性质,对于排列\(P\), 其所形成的每个轮换中的点\(A_i\)是选\(i\)还是选\(P_i\)的状态必须相同。\(Q_i\)同理。
然后转化成最小化\(A_i=B_i\)的位置\(i\)数量。
考虑\(A_i=B_i\)的条件:

(1) \(P_i=Q_i=i\), 则此位置无用,\(A_i=B_i\)一定满足。

(2) \(P_i=i, Q_i\ne i\), 则\(A_i=B_i\)等价于\(B_i=i\).

(3) \(P_i\ne i, Q_i=i\), 则\(A_i=B_i\)等价于\(A_i=i\).

(4) \(P_i=Q_i\ne i\), 则\(A_i=B_i\)等价于\(A_i\)和\(B_i\)选的状态(即是\(i\)还是\(P_i\)或\(Q_i\))不同。

(5) \(P_i\ne Q_i\ne i\), 则\(A_i=B_i\)等价于\(A_i=i\)且\(B_i=i\).

那么我们可以从中观察到一个集合划分模型: 把所有点划分为\(S,T\)两个集合,设\(A_i=i\)表示\(A_i\)在\(S\)集,\(A_i=P_i\)表示\(A_i\)在\(T\)集,\(B_i=i\)表示\(i\)在\(T\)集,\(B_i=Q_i\)表示\(i\)在\(S\)集。那么上述条件就可以转化为:
对每个位置\(i\):

(1) \(P_i=Q_i\), 则此位置无用,一定要花费\(1\)的代价。

(2) \(P_i=i, Q_i\ne i\), 则如果\(B_i\)在\(T\)集需要花费\(1\)的代价。

(3) \(P_i\ne i, Q_i=i\), 则如果\(A_i\)在\(S\)集需要花费\(1\)的代价。

(4) \(P_i=Q_i\ne i\), 则如果\(A_i\)和\(B_i\)在不同的集合要花费\(1\)的代价。

(5) \(P_i\ne Q_i\ne i\), 则如果\(A_i\)在\(S\)集且\(B_i\)在\(T\)集需要花费\(1\)的代价。

于是,给每个轮换建立一个点,再对每个\(i\)分类讨论,将其所对应的轮换连边即可。
由于建出来的图是二分图,且边权都是\(1\), 故时间复杂度\(O(n\sqrt n)\).

我写完之后一直TLE, 最后发现居然是我写了两年的当前弧优化一直是个假的……挂了38发真的是很无语……

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;const int INF = 1e7;namespace NetFlow
{const int N = 2e5+2;const int M = 4e5;struct Edge{int v,w,nxt,rev;} e[(M<<1)+3];int fe[N+3];int te[N+3];int dep[N+3];int que[N+3];int n,en,s,t;void addedge(int u,int v,int w){
//      printf("addedge %d %d %d\n",u,v,w);en++; e[en].v = v; e[en].w = w;e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;en++; e[en].v = u; e[en].w = 0;e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;}bool bfs(){for(int i=1; i<=n; i++) dep[i] = 0;int head = 1,tail = 1; que[1] = s; dep[s] = 1;while(head<=tail){int u = que[head]; head++;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(e[i].w>0 && dep[v]==0){dep[v] = dep[u]+1;if(v==t)return true;tail++; que[tail] = v;}}}return false;}int dfs(int u,int cur){if(u==t||cur==0) {return cur;}int rst = cur;for(int &i=te[u]; i; i=e[i].nxt){int v = e[i].v;if(e[i].w>0 && rst>0 && dep[v]==dep[u]+1){int flow = dfs(v,min(rst,e[i].w));if(flow>0){e[i].w -= flow; rst -= flow;e[e[i].rev].w += flow;if(rst==0) {return cur;}}}}if(rst==cur) {dep[u] = -2;}return cur-rst;}int dinic(int _n,int _s,int _t){n = _n,s = _s,t = _t;int ret = 0;while(bfs()){for(int i=1; i<=n; i++) te[i] = fe[i];memcpy(te,fe,sizeof(int)*(n+1));ret += dfs(s,INF);}return ret;}
}
using NetFlow::addedge;
using NetFlow::dinic;const int N = 1e5;
int a[N+3],b[N+3];
int ca[N+3],cb[N+3];
int n,cnta,cntb;int main()
{scanf("%d",&n);for(int i=1; i<=n; i++) scanf("%d",&a[i]),a[i]++;for(int i=1; i<=n; i++) scanf("%d",&b[i]),b[i]++;for(int i=1; i<=n; i++){if(!ca[i]){cnta++;int x = i;do{ca[x] = cnta;x = a[x];} while(x!=i);}}for(int i=1; i<=n; i++){if(!cb[i]){cntb++;int x = i;do{cb[x] = cntb;x = b[x];} while(x!=i);}}
//  printf("ca: "); for(int i=1; i<=n; i++) printf("%d ",ca[i]); puts("");
//  printf("cb: "); for(int i=1; i<=n; i++) printf("%d ",cb[i]); puts("");int ans = n;for(int i=1; i<=n; i++){if(a[i]==i && b[i]==i) {ans--;}else if(a[i]==i) {addedge(1,cb[i]+cnta+2,1);}else if(b[i]==i) {addedge(ca[i]+2,2,1);}else{addedge(ca[i]+2,cb[i]+cnta+2,1);if(a[i]==b[i]) {addedge(cb[i]+cnta+2,ca[i]+2,1);}}}ans -= dinic(2+cnta+cntb,1,2);printf("%d\n",ans);return 0;
}

AtCoder AGC038F Two Permutations (网络流、最小割)相关推荐

  1. 【bzoj2521】[Shoi2010]最小生成树 网络流最小割

    题目描述 Secsa最近对最小生成树问题特别感兴趣.他已经知道如果要去求出一个n个点.m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法.另外,他还知道,某一个图可能有多种不同的 ...

  2. 【bzoj2132】圈地计划 网络流最小割

    题目描述 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土地是一块矩形的区域,可以纵横划 ...

  3. 洛谷 P1646 [国家集训队]happiness 网络流 最小割 Dinic+当前弧优化

    题目链接: https://www.luogu.com.cn/problem/P1646 参考博客: https://siyuan.blog.luogu.org/solution-p1646 算法:网 ...

  4. AtCoder Regular Contest 107 F - Sum of Abs(网络流最小割)

    题目链接 题意就是给定一个无向图,每个点有权值ai,bia_i,b_iai​,bi​,现在需要删去其中的一些点,其中删去一个点的花费为aia_iai​,删点后的图的分数为每一个联通块的分数之和,一个联 ...

  5. P4897 【模板】最小割树(Gomory-Hu Tree)(网络流/最小割/树形结构)

    P4897 [模板]最小割树(Gomory-Hu Tree) 这个算法可以用来求解一个无向图上任意两点的最小割,具体过程就是每次选择两个点求最小割,然后在一个新图中这两个点连边,然后对于这两个点的连通 ...

  6. CodeForces 1517G Starry Night Camping(网络流最小割)

    CodeForces 1517G Starry Night Camping problem 洛谷链接 solution 这个平行四边形的脑洞我™真的长见识了 本题最离谱的要求就是:平行四边形的一条边平 ...

  7. jzoj4020-Revolution【网络流,最小割】

    正题 题目链接:https://jzoj.net/senior/#contest/show/3014/2 题目大意 n∗mn*mn∗m的地方,每个地方有购买价格和收益,一个地方如果四周都被购买那么也可 ...

  8. 图论 —— 网络流 —— 最小割 —— 平面图与对偶图

    [平面图] 对于一个图 G=(V,E),若其重画后,在平面任意两条边的交点除了图中点外,没有其他交点,那么这个图称为平面图 在平面图中,由边包围并且其中不含顶点的区域称为面 包围面 R 的所有边组成的 ...

  9. Gym - 101982E Cops And Robbers 网络流最小割

    1.题意: 输入一个n行m列的地图,地图上有k种陷阱底座,每种陷阱必须放在相应底座上,并且有一定的花费.有一只兔子初始位置在'B'处,为了使这只兔子不能逃出地图,必须放置一些陷阱来阻拦它.问怎么样放置 ...

最新文章

  1. 命名人工智能最高奖,破译德军密码,却被祖国逼得自杀-6月7日
  2. Windows下Python添加MySQLdb扩展模块
  3. Python LOGGING使用方法
  4. SkinRibbonGalleryBarItem添加无Item问题
  5. EIGRP Metric计算
  6. HTML子div的宽度始终等于父div的宽度
  7. 笔记《精通css》第2章 选择器,注释
  8. Jquery简单的右侧浮动菜单
  9. 最长公共子序列模板(LCS)和LICS模板
  10. ROS学习笔记(八): ROS通信架构
  11. 使用ViewFlipper实现广告图片的自动轮播的效果
  12. 利用图片的 onerror 事件载入默认图片
  13. 本科蓝色学术论文答辩PPT模板
  14. 电商小程序如何实现分账?
  15. 清理android根目录垃圾,安卓清理君——清除手机垃圾
  16. Easyui项目之添加购物车、清空购物车
  17. nnU-Net论文笔记
  18. 什么是“ parentalcontrolsd”,为什么它在我的Mac上运行?
  19. Java基础总结(初学者)
  20. win10如何打开文件扩展名(俗称后缀名)?简单易懂!

热门文章

  1. MindSpore!这款刚刚开源的深度学习框架我爱了!
  2. SVM熟练到精通4:偏离点与松弛变量
  3. 删除数据库中所有存储过程和函数的sql语句
  4. 用Delphi创建服务程序
  5. Delphi中高级DLL的编写和调用
  6. C++中的NULL与DELPHI中的nil作用相同
  7. Beej网络编程指南《三》
  8. C语言中巧妙的使用#和##
  9. STM32单片机工作日记
  10. SpringBoot 页面跳转后css和js效果都无效了