洛谷题面传送门 & Atcoder 题面传送门

好久前做的题了……今天偶然想起来要补个题解

首先考虑排列 \(A_i\) 要么等于 \(i\),要么等于 \(P_i\) 这个条件有什么用。我们考虑将排列 \(P_i\) 拆成一个个置换环,那么对于每一个 \(i\),根据其置换环的情况可以分出以下几类:

  • 如果 \(i\) 所在置换环大小为 \(1\),即 \(P_i=i\),那么 \(A_i\) 别无选择,只能等于 \(i\)
  • 如果 \(i\) 所在置换环大小不为 \(1\),那么 \(A_i\) 有两种选择,\(A_i=i\) 或者 \(A_i=P_i\)
    • 如果 \(A_i=i\),那么假设 \(j\) 为满足 \(P_j=i\) 的位置,那么由于排列中元素不能重复,因此 \(A_j\ne P_j=i\),即 \(A_j=j\),我们再找出 \(P_k=j\) 的 \(k\),也应有 \(A_k=k\),这样即可确定整个置换环上元素的情况。
    • 如果 \(A_i=P_i\),类似地,设 \(j=P_i\),那么 \(A_j\ne j\),因为排列中元素不能重复,故 \(A_j=P_j\),我们再找出 \(k=P_j\) 的位置 \(k\),也应有 \(A_k=P_k\),这样也能够确定整个置换环的 \(A\)。

也就是说,对于一个置换环而言,我们可以将其视作一个整体看待——这个置换环中要么所有元素的 \(A_i\) 都等于其本身,要么所有元素的 \(A_i\) 都等于 \(P_i\),为了使表述更加具体形象,我们把前一种情况称作“转”(orz wlzhouzhuan),后一种情况称作“不转”。那么对于每一个下标 \(i\),它是否产生的 \(A_i=B_i\) 的情况如下:

  • 如果 \(i=P_i=Q_i\),那么不管怎样都有 \(A_i=B_i\),我们完全可以直接令答案加一,并忽略这种情况。
  • 如果 \(i=P_i\ne Q_i\),那么若 \(Q_i\) 所在置换环不转就会有 \(A_i=B_i=i\),对答案产生 \(1\) 的贡献,若 \(Q_i\) 所在置换环转则不会产生这样的情况。
  • 如果 \(i=Q_i\ne P_i\),同理,若 \(P_i\) 所在置换环不转则重复元素个数 \(+1\),否则重复元素个数不变。
  • 如果 \(i\ne P_i=Q_i\),那么如果 \(P_i\) 所在置换环与 \(Q_i\) 所在置换环同时转/同时不转那么重复元素个数 \(+1\),否则重复元素个数不变。
  • 如果 \(i\ne P_i\ne Q_i\),那么如果 \(P_i\) 所在置换环与 \(Q_i\) 所在置换环同时不转那么重复元素个数 \(+1\),否则重复元素个数不变。

如果我们将每个置换环“转”看作被划分入 A 集合,“不转”看作被划分入 B 集合,那么上述条件可以转化为:

  • \(i=P_i\ne Q_i\):如果 \(Q_i\) 所在置换环属于 B 那么答案加 \(1\)
  • \(i=Q_i\ne P_i\):如果 \(P_i\) 所在置换环属于 B 那么答案加 \(1\)
  • \(i\ne P_i=Q_i\):如果 \(P_i,Q_i\) 所在置换环属于相同集合那么答案加 \(1\)
  • \(i\ne P_i\ne Q_i\):如果 \(P_i,Q_i\) 都属于 B 集合那么答案加 \(1\)

看到“划分为两个集合”,“如果两点属于相同/不同集合则代价加 \(1\),求最小/最大代价”之类的字眼,我们能够想到……最小割!具体来说,我们将每个置换环看作一个点,并新建源汇,我们定义 \(P\) 中的置换环转当且仅当其与 \(S\) 相连,不转当且仅当其与 \(T\) 相连;\(Q\) 中的置换环转当且仅当其与 \(T\) 相连,不转当且仅当其与 \(S\) 相连,这样所有代价都可以用一/两条网络流上的 \(1\) 权边的形式表述,再根据最大流 \(=\) 最小割求出最小代价即可。

时间复杂度同 dinic 求二分图匹配,\(\mathcal O(n\sqrt{n})\)。

const int MAXN=1e5;
const int MAXV=1e5+2;
const int MAXE=2e5*2;
const int INF=0x3f3f3f3f;
int n,a[MAXN+5],b[MAXN+5],S=1e5+1,T=1e5+2,ncnt=0;
int bel_a[MAXN+5],bel_b[MAXN+5];
int hd[MAXV+5],to[MAXE+5],cap[MAXE+5],nxt[MAXE+5],ec=1;
void adde(int u,int v,int f){
to[++ec]=v;cap[ec]=f;nxt[ec]=hd[u];hd[u]=ec;
to[++ec]=u;cap[ec]=0;nxt[ec]=hd[v];hd[v]=ec;
} int dep[MAXV+5],now[MAXV+5];
bool getdep(){
memset(dep,-1,sizeof(dep));dep[S]=0;
queue<int> q;q.push(S);now[S]=hd[S];
while(!q.empty()){
int x=q.front();q.pop();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&!~dep[y]){
dep[y]=dep[x]+1;
now[y]=hd[y];q.push(y);
}
}
} return ~dep[T];
}
int getflow(int x,int f){
if(x==T) return f;int ret=0;
for(int &e=now[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&dep[y]==dep[x]+1){
int w=getflow(y,min(f-ret,z));
ret+=w;cap[e]-=w;cap[e^1]+=w;
if(f==ret) return ret;
}
} return ret;
}
int dinic(){
int ret=0;
while(getdep()) ret+=getflow(S,INF);
return ret;
}
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(!bel_a[i]){
bel_a[i]=(i^a[i])?(++ncnt):ncnt;int cur=a[i];
while(cur^i) bel_a[cur]=ncnt,cur=a[cur];
}
for(int i=1;i<=n;i++) if(!bel_b[i]){
bel_b[i]=(i^b[i])?(++ncnt):ncnt;int cur=b[i];
while(cur^i) bel_b[cur]=ncnt,cur=b[cur];
} int res=n;
for(int i=1;i<=n;i++){
if(a[i]==i&&b[i]==i) res--;
else if(a[i]!=i&&b[i]!=i){
if(a[i]==b[i]) adde(bel_a[i],bel_b[i],1),adde(bel_b[i],bel_a[i],1);
else adde(bel_b[i],bel_a[i],1);
} else {
if(a[i]==i) adde(bel_b[i],T,1);
else adde(S,bel_a[i],1);
}
} printf("%d\n",res-dinic());
return 0;
}

Atcoder Grand Contest 038 F - Two Permutations(集合划分模型+最小割)的更多相关文章

  1. AtCoder Grand Contest 038题解

    好久没更了 写点东西吧= = A 01Matrix 简单构造 左上角和右下角染成1其他染成0即可 #include<bits/stdc++.h> #define ll long long ...

  2. AtCoder Grand Contest 038 简要题解

    从这里开始 比赛目录 Problem A 01 Matrix Code #include <bits/stdc++.h> using namespace std; typedef bool ...

  3. AtCoder Grand Contest 038 题解

    传送门 这场表现的宛如一个\(zz\) \(A\) 先直接把前\(b\)行全写成\(1\),再把前\(a\)列取反就行 const int N=1005; char mp[N][N];int n,m, ...

  4. AtCoder Grand Contest 016 F - Games on DAG

    题目传送门:https://agc016.contest.atcoder.jp/tasks/agc016_f 题目大意: 给定一个\(N\)点\(M\)边的DAG,\(x_i\)有边连向\(y_i\) ...

  5. AtCoder Grand Contest 002 F:Leftmost Ball

    题目传送门:https://agc002.contest.atcoder.jp/tasks/agc002_f 题目翻译 你有\(n*k\)个球,这些球一共有\(n\)种颜色,每种颜色有\(k\)个,然 ...

  6. AtCoder Grand Contest 017 F - Zigzag

    题目传送门:https://agc017.contest.atcoder.jp/tasks/agc017_f 题目大意: 找出\(m\)个长度为\(n\)的二进制数,定义两个二进制数的大小关系如下:若 ...

  7. AtCoder Grand Contest 003 F - Fraction of Fractal

    题目传送门:https://agc003.contest.atcoder.jp/tasks/agc003_f 题目大意: 给定一个\(H×W\)的黑白网格,保证黑格四连通且至少有一个黑格 定义分形如下 ...

  8. AtCoder Grand Contest 011 F - Train Service Planning

    题目传送门:https://agc011.contest.atcoder.jp/tasks/agc011_f 题目大意: 现有一条铁路,铁路分为\(1\sim n\)个区间和\(0\sim n\)个站 ...

  9. AtCoder Grand Contest 010 F - Tree Game

    题目传送门:https://agc010.contest.atcoder.jp/tasks/agc010_f 题目大意: 给定一棵树,每个节点上有\(a_i\)个石子,某个节点上有一个棋子,两人轮流操 ...

随机推荐

  1. 巧用 CSS3 filter(滤镜) 属性

    原文链接:CSS3 filter(滤镜) 属性 效果预览 filter: grayscale(100%); 定义和使用 filter 属性定义了元素(通常是<img>)的可视效果(例如:模 ...

  2. 【UE4 C++ 基础知识】<13> 多线程——TaskGraph

    概述 TaskGraph 系统是UE4一套抽象的异步任务处理系统 TaskGraph 可以看作一种"基于任务的并行编程"设计思想下的实现 通过TaskGraph ,可以创建任意多线 ...

  3. 【UE4 设计模式】简单工厂模式 Simple Factory Pattern

    概述 描述 又称为静态工厂方法 一般使用静态方法,根据参数的不同创建不同类的实例 套路 创建抽象产品类 : 创建具体产品类,继承抽象产品类: 创建工厂类,通过静态方法根据传入不同参数从而创建不同具体产 ...

  4. 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索

    骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...

  5. Gitflow branch与Docker image tag命名冲突怎么办?

    谷歌还是比必应要好用一点. 在前公司,我根据主流的git flow 给团队搭建了一套devops流程,运行在 docker & k8s上. 在现代devops流程中,一般推荐使用git分支名或 ...

  6. Noip模拟32(再度翻车) 2021.8.7

    T1 Smooth 很水的一道题...可是最傻    的是考场上居然没有想到用优先队列优化... 上来开题看到这个,最一开始想,这题能用模拟短除法,再一想太慢了,就想着优化 偏偏想到线性筛然后试别的素 ...

  7. PCIE学习链接集合

    <PCIE基础知识+vivado IP core设置> https://blog.csdn.net/eagle217/article/details/81736822 <一步一步开始 ...

  8. word-ladder leetcoder C++

    Given two words (start and end), and a dictionary, find the length of shortest transformation sequen ...

  9. Beam Search快速理解及代码解析

    目录 Beam Search快速理解及代码解析(上) Beam Search 贪心搜索 Beam Search Beam Search代码解析 准备初始输入 序列扩展 准备输出 总结 Beam Sea ...

  10. oracle 账号解锁 java.sql.SQLException: ORA-28000: the account is locked

    日志报错:ORA-28000: the account is locked 1.plsql登录提示用户被锁定 2.sys登录sqlplus登录查看 SQL> select username,ac ...