洛谷题面传送门 & 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. 无网环境安装docker之--rpm

    总体思路:找一台可以联网的linux,下载docker的RPM依赖包而不进行安装(yum localinstall),将所有依赖的rpm环境打包好,再在无网环境中解压逐一安装(rpm:  --forc ...

  2. SpringBoot 01 hello world 01

    hello world项目结构: pom中配置的依赖相当于spring boot的可安装插件,需要下载的依赖直接在里边配置. 目前用到的每个注解: 1.主程序中 @SpringBootApplicat ...

  3. 【UE4 C++】 Config Settings配置文件(.ini)

    简介 常见存储路径 \Engine\Config\ \Engine\Saved\Config\ (运行后生成) [ProjectName]\Config\ [ProjectName]\Saved\Co ...

  4. 【数据结构与算法Python版学习笔记】递归(Recursion)——优化问题与策略

    分治策略:解决问题的典型策略,分而治之 将问题分为若干更小规模的部分 通过解决每一个小规模部分问题,并将结果汇总得到原问题的解 递归算法与分治策略 递归三定律 体现了分支策略 应用相当广泛 排序 查找 ...

  5. [no code][scrum meeting] Alpha 1

    项目 内容 会议时间 2020-04-06 会议主题 团队任务分析与拆解 会议时长 30min 参会人员 全体成员 $( "#cnblogs_post_body" ).catalo ...

  6. Noip模拟72 2021.10.9

    T1 出了个大阴间题 真就以为他出了个大阴间题就没写,打个暴力就跑了 数据范围显然摆明是状压 设$f[sta][0/1]$表示在已经选择的集合$sta$中,$A$的最大值是$A$还是$A+1$ 然后按 ...

  7. JavaScript中的this对象指向理解

    在JavaScript中,this不是固定不变的,它的指向取决于上下文环境,一般的,认为this指向使用它时所在的对象.主要有以下几类指向: 在方法中,this 表示该方法所属的对象. 如果单独使用, ...

  8. greenplum分布键的hash值计算分析

    greenplum 数据分布策略 greenplum 是一个 MPP 架构的数据库,由一个 master 和多个 segment 组成(还可选配置一个 standby master),其数据会根据设置 ...

  9. Register Abstraction(9)

    This post will explain how to use the UVM Register Abstraction Layer (RAL) to generate register tran ...

  10. 转:汇编中EBP寄存器和ESP寄存器的区别

    EBP和ESP都是汇编中关于指针的寄存器.但是定义不同: (1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶.(2 ...