专栏首页数据结构与算法agc016D - XOR Replace(图论 智商)

agc016D - XOR Replace(图论 智商)

题意

题目链接

给出两个长度为$n$的数组$a, b$

每次可以将$a$中的某个数替换为所有数$xor$之和。

若$a$数组可以转换为$b$数组,输出最少操作次数

否则输出$-1$

Sol

一般那看到这种$N \leqslant 10^5$而且不可做的题肯定是先找结论啦

不难看出,我们把所有数$xor$起来的数替换掉之后再次$xor$,得到的一定是被替换掉的数。

实际上,我们可以把xor出来的数放到一个新的位置$N+1$,这样每次操作就变成了交换第$N+1$个位置的数和任意一个位置$x$的数

总的问题就变成了

给出两个长度为$N+1$的数组$a, b$,每次可以在$a$中交换$\forall i \in [1, n]$位置和$N+1$位置的数,问最少交换几次变为$b$数组

首先把$-1$的情况判掉,很显然,把两个数组排序后,若存在一个位置不相同,则一定无解

否则一定有解。

到这里我就不会了。。。。

官方题解非常神仙。

对于$i$位置,若$a_i \not = b_i$,则向$a_i$到$b_i$连一条边

最终答案 = 总边数 + 联通块数 - 1

想一想为什么,对于联通块内的点,假设其大小为$x$,我们一定可以通过$x-1$次操作把他们对应的$a$和$b$变的相同

对于不同联通块之间,我们还需要一步操作使得第$N+1$个位置的数在两个联通块之间转化(第一个除外)

对于第$N+1$个位置需要单独考虑:如果它已经在联通块里则不需要考虑,否则把它看做单独联通块

否则

2
1 3
3 1

可以用并查集维护联通块个数

#include<bits/stdc++.h>
const int MAXN = 4e5 + 10;
using namespace std;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N;
int a[MAXN], b[MAXN], ta[MAXN], tb[MAXN], sa, sb, tot = 0, date[MAXN], fa[MAXN];
map<int, bool> ti;
int find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
int unionn(int x, int y) {
    fa[x] = y;
}
int main() {
    N = read();
    for(int i = 1; i <= N; i++) a[i] = read(), sa ^= a[i]; a[N + 1] = sa;
    for(int i = 1; i <= N; i++) b[i] = read(), sb ^= b[i]; b[N + 1] = sb;
    N++;
    memcpy(ta, a, sizeof(a)); memcpy(tb, b, sizeof(b));
    sort(ta + 1, ta + N + 1); sort(tb + 1, tb + N + 1);
    for(int i = 1; i <= N - 1; i++) if(ta[i] != tb[i]) return puts("-1"), 0;
 
    int ans = 0, num = 0;
    for(int i = 1; i <= N; i++) 
        if(a[i] != b[i] || (i == N)) {
            date[++num] = a[i]; date[++num] = b[i];
            if(i < N)ans++;//最后一块单独考虑
        }
    if(ans == 0) return puts("0"), 0;
 
    sort(date + 1, date + num + 1);
    num = unique(date + 1, date + num + 1) - date - 1;
    for(int i = 1; i <= num; i++) fa[i] = i;
    for(int i = 1; i <= N; i++)
        if(a[i] != b[i]) {
            a[i] = lower_bound(date + 1, date + num + 1, a[i]) - date,
            b[i] = lower_bound(date + 1, date + num + 1, b[i]) - date;
            if(!ti[a[i]]) ti[a[i]] = 1;
            if(!ti[b[i]]) ti[b[i]] = 1;
            unionn(find(a[i]), find(b[i]));
        }
        
    for(int i = 1; i <= num; i++)
        if(fa[i] == i) ans++;
    printf("%d", ans - 1);
 
    return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • cf1027F. Session in BSU(并查集 匈牙利)

    $n$个人,每个人可以在第$a_i$天或第$b_i$,一天最多考一场试,问在最优的情况下,最晚什么时候结束

    attack
  • 洛谷P3358 最长k可重区间集问题(费用流)

    题目描述 ? 对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度。 输入输出格式 输入格式: 的第 1 行有 2 个...

    attack
  • BZOJ3693: 圆桌会议(Hall定理 线段树)

    我的思路:对于区间分两种情况讨论,一种是完全包含,另一种是部分包含。 第一种情况非常好判断,至于计算对于一个区间[l, r]的$\sum a[i]$就可以了,但...

    attack
  • Apache Thrift 白皮书

    • string An encoding-agnostic text or binary string

    WindWant
  • 求int型正整数在内存中存储时1的个数

    Kindear
  • 畅想‘互联网’、‘大数据’会带我们到怎样的世界

    就算我们短期内没有办法空间跳跃,但至少我们会生活的越来越舒服。 我们或多或少也都能想到,我们现在生活中每一种微小的行为都可以被做为有意义的数据进行采集,存储,分...

    企鹅号小编
  • ConcurrentHashMap源码学习

    经过对hashMap的学习,现在我们来学习一下ConcurrentHashMap的机理。我们知道juc包是高并发工具包,按照之前提供的高并发集合,那么Concu...

    程序员_备忘录
  • Android可自定义神奇动效的卡片切换视图实例

    面对众多卡片层叠效果,我们的产品童鞋也突发奇想,搞出了另一种卡片层叠切换展示的交互,而且产品狗们居然要求多做几种动效给他们看,好让他们选择,这简直就是要搞事情啊...

    砸漏
  • 【CodeForces 626E】Simple Skewness

    给出n个数的集合,求一个 (平均数-中位数)最大 (偏度最大)的子集,输出子集元素个数和各个元素(任意顺序)。

    饶文津
  • 并发模型与事件循环 /mdn

    JavaScript 的并发模型基于“事件循环”。这个模型与像 C 或者 Java 这种其它语言中的模型截然不同。

    Jean

扫码关注云+社区

领取腾讯云代金券