嘟嘟嘟
做這題之前,強烈推薦先把這道題切了p1631序列合併。
這兩道題思路基本一模一樣。
首先把異或處理成字首異或,然後維護乙個大根堆,每一次取出堆頂加到答案裡面,然後把堆頂所在元素的次大的異或值放進堆裡。這樣迴圈\(k\)次,就是答案。
關鍵在於對於數\(sum[i]\),怎麼找異或第幾大。眾人皆知是建01trie,然後在trie上像平衡樹找第\(k\)大一樣二分就可以了。因為對於每乙個\(i\),查詢的範圍是\(0\) ~ \(i - 1\),建\(n\)棵trie樹當然不行,所以我們要建一棵可持久化trie樹就好啦。
但是有更好的方法。我們之所以要建可持久化trie樹,就是因為每乙個點的查詢範圍不同,否則建一棵就夠了。那範圍為什麼不同呢?就是為了怕找重。但重了就是每乙個答案算了兩遍,所以我們直接建一棵trie樹,然後迴圈\(2k\)次,然後最後的答案除以2不就是真正的答案了嗎。
#include#include#include#include#include#include#include#include#include#includeusing namespace std;
#define enter puts("")
#define space putchar(' ')
#define mem(a, x) memset(a, x, sizeof(a))
#define in inline
typedef long long ll;
typedef double db;
const int inf = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 5e5 + 5;
const int maxt = 1e7 + 5;
const int n = 31;
inline ll read()
inline void write(ll x)
in void myfile()
int n, k;
ll a[maxn], sum[maxn];
ll b[maxn], cnt = 0;
in void work0()
sort(b + 1, b + cnt + 1);
ll ans = 0;
for(int i = cnt; i >= cnt - k + 1; --i) ans += b[i];
write(ans), enter;
}struct node
};priority_queueq;
struct tree
t[maxt];
int root, tcnt = 0;
in void insert(int& now, ll x, int d)
insert(t[now].ch[(x >> d) & 1], x, d - 1);
t[now].siz = t[t[now].ch[0]].siz + t[t[now].ch[1]].siz;
}in ll query(ll x, int k)
return ret;
}int main()
for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] ^ a[i];
for(int i = 0; i <= n; ++i) insert(root, sum[i], n);
for(int i = 0; i <= n; ++i)
q.push((node));
ll ans = 0;
for(int i = 1; i <= (k << 1); ++i));}
write(ans >> 1), enter;
return 0;
}
十二省聯考 2019 異或粽子
題目鏈結 演算法 首先把字首異或和統計出來,再將得到的每乙個字首異或和 包括pre 0 0 塞進字典樹中,接下來有乙個貪心的思路 每當我拿著其中乙個異或和的值時,我在字典樹中盡可能找二進位制高位與其對應的位不相同的異或和,這樣兩者異或運算後,所得值最大。所以我們有了這樣乙個思路,對於每乙個pre i...
十二省聯考2019 異或粽子
點此看題 方法1 發現這道題k kk很小,先考慮用字首和表示異或和,建出一顆tire text tire 樹,然後把每個點的最優值丟進優先佇列中 因為其他值沒有這個值優 然後依次取出,再把次大值塞進去。由於每個區間會被統計兩次,所以我們找2k2k 2k次,最後把答案除以2 22即可。方法2 和k k...
十二省聯考2019 異或粽子
其實和超級鋼琴那個題思路挺像的,就是我們弄乙個二元組,乙個pos,乙個sum。求一下字首異或和,然後在它pos前面的01trie裡面查詢第k大即可。如下 luogu judger enable o2 include include include include include include de...