P3430 [POI2005]DWU-Double-row

题意:给定长为 $n$ 的序列 $a,b$,你可以选定 $m$ 个位置 $p_i$ 交换 $a_{p_i},b_{p_i}$,使得 $a$ 中不存在相同元素,$b$ 中同理。最小化 $m$。


看到相等,不等,二元运算。好啊,非常显然,建图!问题来了,怎么建图?

什么是点?把同一个位置上的 $a_i,b_i$ 看成一个点。

什么是边?考虑如果两个点的位置有相同元素则建边。怎么区分同位与异位?$0/1$ 边权!

也就是说,如果 $a_u=a_v$ 或 $b_u=b_v$ 则 $u,v$ 建一条边权为 $1$ 的边,否则边权为 $0$。

至此建图完成。


建完图了,现在怎么做?

考虑一次操作,图有什么变化。

对一个位置 $u$ 的 $a_u,b_u$ 交换,那么与其相连的同位变成异位,异位变成同位,也就是与其相邻的所有边边权取反。

既然最终全都不同,那么最终状态就是边权全部为 $0$。

瞎口胡了一下,到这里好像就可以高消做了,然而我不会也不知道对不对。/kk


于是这里有一个套路化的想法就是对于每个点黑白染色,钦定一个连通块上任意一个点为白色($c_i=0$)。

  • 若 $u$ 到 $v$ 的边权为 $1$ 则 $c_u\neq c_v$。

  • 若 $u$ 到 $v$ 的边权为 $0$ 则 $c_u= c_v$。

这样我们对所有白色结点操作一遍,或者对所有黑色结点操作一遍都可以达到边权全部为 $0$ 的效果。

正确性证明:对于一条边,如果边权为 $1$ 那么其两个端点一定一个为 $0$ 一个为 $1$,这条边会被操作一次变成 $0$。如果边权为 $0$,则会被这条边要么不被操作要么被取反两次,还是 $0$。

所以一个连通块边权为 $0$ 的最小代价为白色结点数量与黑色结点数量的较小者。

跑 dfs 即可。


#include <bits/stdc++.h>

using namespace std;

const int maxn = 5e5 + 10;
const int maxv = 1e6 + 10;

struct edge { int to, next, w; };

int n, ans;
int a[maxn], b[maxn];
vector<int> p[maxv];
int head[maxn];
edge e[maxn << 2];
int cnt;

void add_edge(int u, int v, int w) {
    e[++cnt] = {v, head[u], w};
    head[u] = cnt;
}

int vis[maxn], c[2];

void dfs(int u, int f) {
    ++c[f];
    vis[u] = true;
    for (int i = head[u]; i; i = e[i].next) {
        int v = e[i].to, w = e[i].w;
        if (!vis[v]) dfs(v, f ^ w);
    }
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) cin >> b[i];
    for (int i = 1; i <= n; i++) if (a[i] != b[i]) p[a[i]].push_back(i), p[b[i]].push_back(i);
    for (int i = 1; i < maxv; i++) {
        if (p[i].size() == 2) {
            int u = p[i][0], v = p[i][1], f = (a[u] == a[v] || b[u] == b[v]);
            add_edge(u, v, f), add_edge(v, u, f);
        }
    }
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            c[0] = c[1] = 0;
            dfs(i, 0);
            ans += min(c[0], c[1]);
        }
    }
    cout << ans << endl;
    return 0;
}
posted @   TernaKagiri  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示