题目大意:
给出两个排列
P
,
Q
P,Q
P,Q.要求构造两个排列
A
,
B
.
A,B.
A,B.
要求:
A
i
Ai
Ai要么等于
i
i
i,要么等于
P
i
Pi
Pi;
B
i
Bi
Bi要么等于
i
i
i,要么等于
Q
i
Qi
Qi
最大化
A
i
≠
B
i
Ai≠Bi
Ai=Bi的下标
i
i
i数量
1e5我都不敢相信这也可以用网络流!!!
这道题看起来无从下手那么我们就分类讨论来看一下
但是发现直接讨论
A
i
≠
B
i
A_i≠B_i
Ai=Bi很麻烦,那么问题先变成球最小化
A
i
=
B
i
A_i=B_i
Ai=Bi再用
n
n
n减掉就好了
- P i = Q i = i P_i=Q_i=i Pi=Qi=i 这个时候无论你选什么 A i 一 定 是 等 于 B i A_i一定是等于B_i Ai一定是等于Bi
- P i = i & & Q i ≠ i P_i=i\&\&Q_i≠i Pi=i&&Qi=i 那么如果 O i = i O_i=i Oi=i的话那么这里就会有1个的相等的位置
- Q i = 1 & & P i ≠ i Q_i=1\&\&P_i≠i Qi=1&&Pi=i 那么如果这里 P i = i P_i=i Pi=i的话那么这里就会有1个相等的位置
- Q i ≠ P i ≠ i Q_i≠P_i≠i Qi=Pi=i 那么只有 P i = Q i = i P_i=Q_i=i Pi=Qi=i的时候才会有一个相等的位置
- Q i = P I ≠ i Q_i=P_I≠i Qi=PI=i那么只要取 P i 和 Q i P_i和Q_i Pi和Qi 或者都取 i i i的时候那么就是有1个相等的位置
但是有一点就是因为
A
i
和
B
i
A_i和B_i
Ai和Bi也是全排列!!
注意原题的排列是从0开始的,为讨论方便,我们统一转化为从1开始的。
考虑对于每个排列,把i向Pi连边,那么就会形成很多个环。比如排列
3
,
2
,
4
,
1
{3,2,4,1}
3,2,4,1,其中3,4,1和2分别形成两个环1−3−4−1和2−2。我们令
A
i
=
P
i
A_i=P_i
Ai=Pi,实际上就是把环上的数Pi选转过来(当然理解成把i转过来也可以,只是环上点权设置的问题).。对于一个环,环上的点选择的方案应该是一致的(全都等于i或全都不等于i),否则就会存在某个数不合法。
现在我们令两个集合
S
,
T
S,T
S,T。
对于
P
P
P数组中的第
i
i
i个数
P
i
P_i
Pi如果放入S集合里面相当于
A
i
A_i
Ai选
P
i
P_i
Pi,放入T集合相当于
A
i
A_i
Ai选
i
i
i
对于
Q
Q
Q数组就反过来,如果放入S集合里面相当于
B
i
B_i
Bi选
i
i
i,放入T集合相当于
B
i
B_i
Bi选
Q
i
Q_i
Qi
那么上面的问题就可以转化了
因为是求最小化的位置相同个数!
那么就是最小割,对于每条边我们都赋予割了它的实际意义,那么满足的最小化就是最小割了!!
因为对于同一个轮换里面的位置选的都是一样的那么我们直接用轮换的下标去代替就好了
- P i = Q i = i P_i=Q_i=i Pi=Qi=i 这个时候无论你选什么 A i 一 定 是 等 于 B i A_i一定是等于B_i Ai一定是等于Bi ans 直接减1
- P i = i & & Q i ≠ i P_i=i\&\&Q_i≠i Pi=i&&Qi=i 那么如果 Q i = i Q_i=i Qi=i的话那么这里就会有1个的相等的位置,那么就是 Q i Q_i Qi放到S集合里面代价是1,反过来放在T集合就是代价就是0;
- Q i = 1 & & P i ≠ i Q_i=1\&\&P_i≠i Qi=1&&Pi=i 那么如果这里 P i = i P_i=i Pi=i的话那么这里就会有1个相等的位置,同理!
- Q i = P I ≠ i Q_i=P_I≠i Qi=PI=i那么只要取 P i 和 Q i P_i和Q_i Pi和Qi 或者都取 i i i的时候那么就是有1个相等的位置,那么按照上的集合划分就是在如果 P i 和 Q i P_i和Q_i Pi和Qi在不同的集合里面代价为1.
- Q i ≠ P i ≠ i Q_i≠P_i≠i Qi=Pi=i 那么只有 P i = Q i = i P_i=Q_i=i Pi=Qi=i的时候才会有一个相等的位置,那么就是 P i P_i Pi在S集合里面, Q i Q_i Qi在T集合里面
那么就参考集合冲突模型的建图模型
- 直接建图就可以了!!
- Q i − > T 流 量 为 1 Q_i->T流量为1 Qi−>T流量为1 S − > P i 流 量 为 0 S->P_i流量为0 S−>Pi流量为0
- Q i − > T 流 量 为 0 Q_i->T流量为0 Qi−>T流量为0 S − > P i 流 量 为 1 S->P_i流量为1 S−>Pi流量为1
- P i − > Q i 流 量 为 1 P_i->Q_i流量为1 Pi−>Qi流量为1 Q i − > P i 流 量 为 1 Q_i->P_i流量为1 Qi−>Pi流量为1
- Q i − > P i 流 量 为 1 Q_i->P_i流量为1 Qi−>Pi流量为1
代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct node {
int to, next, len;
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
e[cnt] = {to,head[from],len};
head[from] = cnt ++;
}
int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];
bool bfs() {
ms(d,0);
queue<int> q;
q.push(s); d[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[v] || e[i].len <= 0) continue;
q.push(v);
d[v] = d[u] + 1;
}
}
for(int i = 0; i <= n; ++ i) cur[i] = head[i];
return d[t] != 0;
}
int dfs(int u, int flow) {
if(u == t) return flow;
for(int &i = cur[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
int delta = dfs(v,min(flow,e[i].len));
if(delta <= 0) continue;
e[i].len -= delta;
e[i^1].len += delta;
return delta;
}
return 0;
}
int get_maxflow() {
int maxFlow = 0, delta;
while(bfs())//bfs进行构建最短路网络
while(delta = dfs(s,INF))
maxFlow += delta;
return maxFlow;
}
int P[maxn], Q[maxn];
int Cle;//统计环的个数
int idp[maxn]; // p数组中每个数在哪个环里面
int idq[maxn]; // q数组中每个数在哪个
int main() {
IOS;
ms(head,-1);
int tn;
cin >> tn;
for(int i = 1; i <= tn; ++ i)
cin >> P[i], P[i] ++;
for(int i = 1; i <= tn; ++ i)
cin >> Q[i], Q[i] ++;
for(int i = 1; i <= tn; ++ i) {
if(idp[i]) continue;
Cle ++;
int idx = i;
do {
idp[idx] = Cle;
idx = P[idx];
}while(idx != i);
}
for(int i = 1; i <= tn; ++ i) {
if(idq[i]) continue;
Cle ++;
int idx = i;
do {
idq[idx] = Cle;
idx = Q[idx];
}while(idx != i);
}
int ans = tn;
s = 0, t = Cle+1;
n = 2*tn+1;
for(int i = 1; i <= tn; ++ i) {
if(P[i] == i && Q[i] == i) ans --;
else if(P[i] == i) {
add(idq[i],t,1);
add(t,idq[i],0);
//可有可不有
add(s,idq[i],0);
add(idq[i],s,0);
} else if(Q[i] == i) {
add(s,idp[i],1);
add(idp[i],s,0);
//可有可不有
add(idp[i],t,0);
add(t,idp[i],0);
} else if(Q[i] == P[i]) {
add(idp[i],idq[i],1);
add(idq[i],idp[i],0);
add(idq[i],idp[i],1);
add(idp[i],idq[i],0);
} else {
add(idq[i],idp[i],1);
add(idp[i],idq[i],0);
}
}
cout << ans - get_maxflow();
return 0;
}