1 条题解
-
0
自动搬运
来自洛谷,原作者为

Gold_Dino
意定克艰,志定克难,行必胜忧,思必胜劳搬运于
2025-08-24 22:32:50,当前版本为作者最后更新于2025-07-29 11:25:41,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
非常板子的一道题(但是卡空间
题意
你有一个未知序列 ,你现在知道若干个操作和对应的结果:
-
操作一:将序列中某个数的二进制位做循环位移。
-
操作二:告诉你序列中两个数的异或和。
求字典序最小的初始序列。
思路
涉及二进制,考虑对于每个二进制位单独考虑。
先不考虑操作一,那么异或操作,相当于告诉了若干对二进制位是否相等。
这启发我们可以把每个数的二进制位看成图上的若干个点,相等的点连边。
但是每个二进制位有 和 两种取值,所以可以拆点。形式化地,对于 的二进制第 位,建两个点 和 分别表示取值与第 位相等,或者等于第 位取反。
那么如果两个位置相等,它们取反后也相等。而如果数位 和数位 不同,则 ,所以可以交叉建边。
而加上操作一也是简单的,直接把循环位移的偏移量记录下来,在操作二建边的时候考虑一下就行了。
现在我们得到一张图,连边表示点权相同,可以用并查集来维护。
考虑判断无解,发现如果 与 在同一个连通分量中,那么肯定无解(显然,一个数位不可能和它取反后相等),而其他情况一定有解。
考虑贪心构造最小字典序,肯定从 枚举到 ,再贪心的让最高位尽量为 。考虑一个数位 ,如果该数位的连通分量中的其他数位都没有被访问过,那么该位置一定可以为 ,同时,将 和 所在的连通分量标记一下,表示这个连通分量已经被赋值过了,下次访问到连通分量中的点,只能取某个固定的值。
注意要用
unsigned int代码
#include <bits/stdc++.h> using namespace std; typedef unsigned u32; // #define int u32 const int maxN = int(1e5+7); const int V = maxN*64; int n, e; u32 ans[maxN]; int rot[maxN]; int fa[V]; int find(int x) { return fa[x] <= 0 ? x : fa[x] = find(fa[x]); } void merge(int u, int v) { if (find(u) == find(v)) return; fa[find(u)] = find(v); } int main() { scanf("%d%d", &n, &e); auto id = [=](int n, int p, int b) { int x = (n-1)*32+p+1; if (b) x += ::n*32; return x; }; for (int cas = 1; cas <= e; ++cas) { int opt, k, l; scanf("%d%d%d", &opt, &k, &l); if (opt == 1) { rot[k] = (rot[k] + l) % 32; } if (opt == 2) { u32 res; scanf("%u", &res); for (int i = 0; i < 32; ++i) { int val = (res>>i)&1; if (!val) { merge(id(k, (i+rot[k])%32, 0), id(l, (i+rot[l])%32, 0)); merge(id(k, (i+rot[k])%32, 1), id(l, (i+rot[l])%32, 1)); } else { merge(id(k, (i+rot[k])%32, 0), id(l, (i+rot[l])%32, 1)); merge(id(k, (i+rot[k])%32, 1), id(l, (i+rot[l])%32, 0)); } } } } bool flag = false; for (int i = 1; i <= n; ++i) { for (int j = 0; j < 32; ++j) { if (find(id(i, j, 0)) == find(id(i, j, 1))) flag = true; } assert(id(i, 31, 0) <= n*32); } if (flag) { printf("-1\n"); } else { for (int i = 1; i <= n; ++i) { for (int j = 31; ~j; --j) { if (fa[find(id(i, j, 0))] == 0) { fa[find(id(i, j, 0))] = -1; fa[find(id(i, j, 1))] = -2; } else { if (fa[find(id(i, j, 0))] == -2) { ans[i] += (1u<<j); } } } } for (int i = 1; i <= n; ++i) printf("%u%c", ans[i], " \n"[i == n]); } return 0; } -
- 1
信息
- ID
- 7071
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者