CF1163E Magical Permutation
2024-09-04 00:17:09
题意:给定集合,求一个最大的x,使得存在一个0 ~ 2x - 1的排列,满足每相邻的两个数的异或值都在S中出现过。Si <= 2e5
解:若有a,b,c,令S1 = a ^ b, S2 = b ^ c,则有a ^ c = S1 ^ S2
因为有0存在,所以每个数都能表示成它到0路径上的所有间隔的异或和,也就是每个数都能被表示出来。我们用线性基来判断。
找到最大的x之后,我们可以发现,线性基中x个数的2x种选法一一对应这2x个数。于是直接采用格雷码来找这个排列,每加一位,就在x个数中添加 / 删除一个数到异或集合中。
我的实现较复杂。实际上只要把线性基这x个数记下来,格雷码的时候选择是否异或即可。
#include <bits/stdc++.h> const int N = ; int n, a[N], base[], T, id[], sta[N], pos[N], s; inline void clear() {
memset(base, , sizeof(base));
memset(id, , sizeof(id));
return;
} inline void insert(int x, int v) {
int V = ;
for(int i = T - ; i >= ; i--) {
if(!((x >> i) & )) {
continue;
}
if(base[i]) {
x ^= base[i];
V ^= id[i];
}
else {
base[i] = x;
id[i] = V | ( << i);
break;
}
}
return;
} inline bool check() {
for(int i = T - ; i >= ; i--) {
if(!base[i]) {
return false;
}
}
return true;
} inline void find(int x) {
int t = x;
for(int i = T - ; i >= ; i--) {
if(!((x >> i) & )) {
continue;
}
x ^= base[i];
sta[t] ^= id[i];
}
return;
} void DFS(int k) {
if(k == -) {
printf("%d ", pos[s]);
return;
}
DFS(k - );
s ^= << k;
DFS(k - );
return;
} int main() {
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
}
std::sort(a + , a + n + );
int fin = ;
for(T = ; T <= ; T++) {
int lm = ( << T) - ;
clear();
for(int i = ; i <= n && a[i] <= lm; i++) {
insert(a[i], i);
}
if(check()) {
fin = T;
}
}
T = fin;
/// T
int lm = ( << T) - ;
for(int i = ; i <= lm; i++) {
find(i);
pos[sta[i]] = i;
}
printf("%d\n", T);
DFS(T - );
puts("");
return ;
}
AC代码
最新文章
- 【MongoDB初识】-其他操作
- java 深度遍历文件夹中的所有文件
- Oracle备份表结构和数据
- POJ 2065 SETI(高斯消元)
- 通过history.pushState无刷新改变url
- iOS 打印日志的保存 (一)
- 彻底清除Linux centos minerd木马
- Java多线程之赛跑游戏
- rhel7 配置普通用户使用sudo
- 深入浅出Tabhost+简单入门Demo
- JAVA程序设计的第一次作业
- 程序员基层知识程序与cpu【更新1】
- FreeMarker生成Word文档
- 21 week4 submit buidAndRun() node-rest-client
- Docker手动搭建sentry错误日志系统
- IntelliJ IDEA 连接数据库 详细过程
- LCS 最长公共子子串
- hiho一下 第二周 trie树
- leecode刷题(22)-- 反转数组
- JavaScript es6 class类的理解。