知识
1.或运算:有一个数为1,结果为1
所以贪心:尽量让高位为0(从高位到低位),这样就可以求e的最小值
2.异或:相同为0,不同为1(1有奇数个,则值为1;1有偶数个,则值为0)
选分割点时,如果前面的区间异或和为0,则从此处分开(因为贪心规则是尽量让高位为0)
即如果求得异或和为0的区间>m个,则可以合并某些区间来使异或和为0的区间=m个,这样使e为最小值0。
如果求得异或和为0的区间<m个
3.前缀和:a[i]存数,b[i]存异或和的前缀和。遍历位数。
若b[i-1]=0,则下一个区间不用减去i-1部分,即直接使用b[i]即可。(找一些分割点使区间为0)
再找一些不可以的分割点,这样之后的遍历就可以跳过了。
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 5e5 + 10; int n, m, ans; int a[N],b[N]; bool st[N]; // 记录不可分割点 signed main() { cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; } for (int i = 1; i <= n; i++) { b[i] = b[i - 1]^a[i]; } for (int i = 62; i >= 0; i--) { // 遍历每一位(62是根据a的数据范围得出的) int cnt = 0; // 分割点个数 for (int j = 1; j <= n; j++) { if (!st[j] && !(b[j] & (1LL << i))) // 分割点使可行的并且这一区间为0 cnt++; } if (cnt >= m && !(b[n] & (1LL << i))) // 此位为0 // cnt>=m:分割点>=m,所以结果为0 { // 看整个的异或和。即看总共异或和是否为0,若不为0则说明有奇数个1,最后结果不可能为0 for (int j = 1; j <= n; j++) { // 看哪些点是不可分割点 if (b[j] & (1LL << i)) { st[j] = 1; } } } else { // 此位为1 ans |= 1ll << i; } } cout << ans; }