@description@

给定 N 与两个 0~N-1 的置换 P, Q。

现在你需要找到两个置换 A 与 B,使得 A[i] = P[i] 或 i;B[i] = Q[i] 或 i。

最大化 A[i] ≠ B[i] 的 i 的数量。 输出最大值。

Constraints

1 ≤ N ≤ 100000。

保证 P 为 0~N-1 的排列。

保证 Q 为 0~N-1 的排列。

Input

输入形式如下:

N

P0 P1 ⋯ PN−1

Q0 Q1 ⋯ QN−1

Output

输出 A[i] ≠ B[i] 的 i 的最大数量。

Sample Input 1

4

2 1 3 0

0 2 3 1

Sample Output 1

3

一种方案为 A=(0,1,2,3), B=(0,2,3,1)。

Sample Input 2

10

0 4 5 3 7 8 2 1 9 6

3 8 5 6 4 0 2 1 7 9

Sample Output 2

8

Sample Input 3

32

22 31 30 29 7 17 16 3 14 9 19 11 2 5 10 1 25 18 15 24 20 0 12 21 27 4 26 28 8 6 23 13

22 3 2 7 17 9 16 4 14 8 19 26 28 5 10 1 25 18 15 13 11 0 12 23 21 20 29 24 27 6 30 31

Sample Output 3

28

@solution@

对于置换 P,我们将其分解成若干循环。

则对于每一个循环,要么同时选择变成 i, 要么同时保持 P[i] 不变。

每个元素有两种选择,而选择之间会互相影响,让人不是想到 2-sat 就是想到最小割(而时限又进一步地暗示最小割!)。

最小割的转化:我们求最小的 A[i] = B[i] 的数量。

对于每个循环,我们建个虚点,向循环内所有点连容量为 inf 的双向边。

剩下的就是一个经典的二元关系建图(即:同时选会产生代价之类的问题)。

对于每个 Pi,源点连向它表示选 i,它连向汇点表示选 Pi。

对于每个 Qi,源点连向它表示选 Qi,它连向汇点表示选 i。

然后根据 i, Pi, Qi 之间的相等关系分类建边。具体可以看代码。

至于为什么不对称着建,因为对称着建会产生负权边,就不大好。

@accepted code@

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int INF = (1<<30);
struct FlowGraph{
struct edge{
int to, cap, flow;
edge *nxt, *rev;
}edges[20*MAXN + 5], *adj[4*MAXN + 5], *cur[4*MAXN + 5], *ecnt;
FlowGraph() {ecnt = &edges[0];}
void addedge(int u, int v, int c1, int c2) {
edge *p = (++ecnt), *q = (++ecnt);
p->to = v, p->cap = c1, p->flow = 0;
p->nxt = adj[u], adj[u] = p;
q->to = u, q->cap = c2, q->flow = 0;
q->nxt = adj[v], adj[v] = q;
p->rev = q, q->rev = p;
// printf("! %d %d %d %d\n", u, v, c1, c2);
}
int dis[4*MAXN + 5];
int s, t;
bool relabel() {
for(int i=0;i<=t;i++)
dis[i] = INF, cur[i] = adj[i];
queue<int>que; que.push(t), dis[t] = 0;
while( !que.empty() ) {
int f = que.front(); que.pop();
for(edge *p=adj[f];p;p=p->nxt)
if( p->rev->cap > p->rev->flow )
if( dis[f] + 1 < dis[p->to] )
que.push(p->to), dis[p->to] = dis[f] + 1;
}
return !(dis[s] == INF);
}
int aug(int x, int tot) {
if( x == t ) return tot;
int sum = 0;
for(edge *&p=cur[x];p;p=p->nxt) {
if( p->cap > p->flow && dis[p->to] + 1 == dis[x] ) {
int del = aug(p->to, min(p->cap - p->flow, tot - sum));
sum += del, p->flow += del, p->rev->flow -= del;
if( sum == tot ) break;
}
}
return sum;
}
int max_flow(int _s, int _t) {
int flow = 0; s = _s, t = _t;
while( relabel() )
flow += aug(s, INF);
return flow;
}
}G;
int P[MAXN + 5], Q[MAXN + 5];
bool tag[MAXN + 5];
int main() {
int N, cnt; scanf("%d", &N), cnt = 2*N;
for(int i=1;i<=N;i++)
scanf("%d", &P[i]), P[i]++, tag[i] = false;
for(int i=1;i<=N;i++)
if( !tag[i] ) {
int p = i; cnt++;
do {
tag[p] = true;
p = P[p];
G.addedge(cnt, p, INF, INF);
}while( p != i );
}
for(int i=1;i<=N;i++)
scanf("%d", &Q[i]), Q[i]++, tag[i] = false;
for(int i=1;i<=N;i++)
if( !tag[i] ) {
int p = i; cnt++;
do {
tag[p] = true;
p = Q[p];
G.addedge(cnt, p + N, INF, INF);
}while( p != i );
}
int s = 0, t = cnt + 1;
for(int i=1;i<=N;i++) {
if( i == P[i] && i == Q[i] && P[i] == Q[i] )// a = c = 1
G.addedge(s, i, 1, 0), G.addedge(i, t, 1, 0);
if( i == P[i] && i != Q[i] && P[i] != Q[i] )// b = 1
G.addedge(s, i + N, 1, 0);
if( i != P[i] && i == Q[i] && P[i] != Q[i] )// c = 1
G.addedge(i, t, 1, 0);
if( i != P[i] && i != Q[i] && P[i] == Q[i] )// e = f = 1
G.addedge(i, i + N, 1, 1);
if( i != P[i] && i != Q[i] && P[i] != Q[i] )// f = 1
G.addedge(i, i + N, 1, 0);
}//s -> i(a), s -> i+N(b), i -> t(c), i+N -> t(d), i+N -> i(e), i -> i+N(f)
printf("%d\n", N - G.max_flow(s, t));
}

@details@

怎么感觉 F 题比 E 题水啊。是我的错觉吗。

@atcoder - AGC038F@ Two Permutations的更多相关文章

  1. AtCoder AGC038F Two Permutations (网络流、最小割)

    题目链接 https://atcoder.jp/contests/agc038/tasks/agc038_f 题解 好题. 首先观察到一个性质,对于排列\(P\), 其所形成的每个轮换中的点\(A_i ...

  2. AtCoder AGC031D A Sequence of Permutations (群论、置换快速幂)

    题目链接 https://atcoder.jp/contests/agc031/tasks/agc031_d 题解 这居然真的是个找规律神题... 首先要明白置换的一些基本定义,置换\(p\)和\(q ...

  3. Atcoder Grand Contest 038 F - Two Permutations(集合划分模型+最小割)

    洛谷题面传送门 & Atcoder 题面传送门 好久前做的题了--今天偶然想起来要补个题解 首先考虑排列 \(A_i\) 要么等于 \(i\),要么等于 \(P_i\) 这个条件有什么用.我们 ...

  4. Atcoder Grand Contest 031 D - A Sequence of Permutations(置换+猜结论)

    Atcoder 题面传送门 & 洛谷题面传送门 猜结论神题. 首先考虑探究题目中 \(f\) 函数的性质,\(f(p,q)_{p_i}=q_i\leftarrow f(p,q)\circ p= ...

  5. Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations

    题意: 对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s 现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定. 现在 ...

  6. AtCoder Grand Contest 031 (AGC031) D - A Sequence of Permutations 其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/AGC031D.html 前言 比赛的时候看到这题之后在草稿纸上写下的第一个式子就是 $$f(p,q) = pq^ ...

  7. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  8. Permutations II

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  9. [LeetCode] Permutations II 全排列之二

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

随机推荐

  1. 20190815-$N \Theta IP$

    $NOIP$ 请选择您想测试的难度: 「困难」 「困难的地狱」 「能被神犇切掉的」 「你做不出来的」 「简单(完成前面所有后解锁)」 要难死了-- 考试过程: 首先看看三道题: 这是NOIP模拟测试? ...

  2. 从零开始Android逆向教程(二)——什么是Xposed

    前言在阅读本文之前,假设你的手机已经root,并且已经成功安装好了 XposedInstaller. Xposed是什么?       Xposed 是一个 Android 平台上的动态劫持框架,通过 ...

  3. Oil Deposits HDU - 1241 (dfs)

    Oil Deposits HDU - 1241 The GeoSurvComp geologic survey company is responsible for detecting undergr ...

  4. Jboss配置HTTPS

    配置jboss的HTTP请求走SSL(HTTPS协议) l         生成keystore 文件 用keytool生成server.keystore文件: 进入命令行 C:\Documents ...

  5. SpringCloud微服务实战一:Spring Cloud Eureka 服务发现与注册中心(高可用实列为两个注册中心)

    微服务架构: 微服务架构的核心思想是,一个应用是由多个小的.相互独立的.微服务组成,这些服务运行在自己的进程中,开发和发布都没有依赖.不同服务通过一些轻量级交互机制来通信,例如 RPC.HTTP 等, ...

  6. ssh连接超时中断问题解决方案

    当在终端使用ssh命令连接到服务器时,如果一段时间没有活动连接会被中断,以下有两种方案可以解决: 一.修改ssh客户端配置 编辑客户端 /etc/ssh/ssh_config (或~/.ssh/con ...

  7. Linux远程管理Windows程序Rdesktop详解

    #rpm –q rdesktop                       //查找是否已经安装 #yum install rdesktop                //使用yum安装 rde ...

  8. 将自己的代码托管到github - 秦时明月 - CSDN博客

    步骤: 1.建立自己的github 2.安装github客户端,并配置身份 3.建立github项目 4.将github项目库下载到本地 5.提交本地代码到github 详细操作: 1.github网 ...

  9. Vue Router 相关

    1. 路由传参: 编程式的导航 router.push this.$router.push("home"); this.$router.push({ name: 'news', p ...

  10. 存储过程--mysql

    https://zhuanlan.zhihu.com/p/23423264 存储过程-官方解释: 是sql语句和控制语句的预编译集合.以一个名称存储并作为一个单元处理. 存储过程-直白的说: 把需要的 ...