CF1163E Magical Permutation

题意:给定集合,求一个最大的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个数记下来,格雷码的时候选择是否异或即可。

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 500010;
 4 
 5 int n, a[N], base[64], T, id[64], sta[N], pos[N], s;
 6 
 7 inline void clear() {
 8     memset(base, 0, sizeof(base));
 9     memset(id, 0, sizeof(id));
10     return;
11 }
12 
13 inline void insert(int x, int v) {
14     int V = 0;
15     for(int i = T - 1; i >= 0; i--) {
16         if(!((x >> i) & 1)) {
17             continue;
18         }
19         if(base[i]) {
20             x ^= base[i];
21             V ^= id[i];
22         }
23         else {
24             base[i] = x;
25             id[i] = V | (1 << i);
26             break;
27         }
28     }
29     return;
30 }
31 
32 inline bool check() {
33     for(int i = T - 1; i >= 0; i--) {
34         if(!base[i]) {
35             return false;
36         }
37     }
38     return true;
39 }
40 
41 inline void find(int x) {
42     int t = x;
43     for(int i = T - 1; i >= 0; i--) {
44         if(!((x >> i) & 1)) {
45             continue;
46         }
47         x ^= base[i];
48         sta[t] ^= id[i];
49     }
50     return;
51 }
52 
53 void DFS(int k) {
54     if(k == -1) {
55         printf("%d ", pos[s]);
56         return;
57     }
58     DFS(k - 1);
59     s ^= 1 << k;
60     DFS(k - 1);
61     return;
62 }
63 
64 int main() {
65     scanf("%d", &n);
66     for(int i = 1; i <= n; i++) {
67         scanf("%d", &a[i]);
68     }
69     std::sort(a + 1, a + n + 1);
70     int fin = 0;
71     for(T = 0; T <= 18; T++) {
72         int lm = (1 << T) - 1;
73         clear();
74         for(int i = 1; i <= n && a[i] <= lm; i++) {
75             insert(a[i], i);
76         }
77         if(check()) {
78             fin = T;
79         }
80     }
81     T = fin;
82     /// T 
83     int lm = (1 << T) - 1;
84     for(int i = 1; i <= lm; i++) {
85         find(i);
86         pos[sta[i]] = i;
87     }
88     printf("%d\n", T);
89     DFS(T - 1);
90     puts("");
91     return 0;
92 }
AC代码

 

posted @ 2019-06-27 15:41  huyufeifei  阅读(309)  评论(3编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜