题目
给定若干个自然数 a1∼n。
你需要选出其中一些数,然后将你选出的数划分为若干个集合。
你需要最大化每个集合 mex 的异或和,输出这个值。
一个集合的 mex 是指最小的不在这个集合中的自然数,例如 {0,1,2,4,5} 的 mex 是 3,{1,2,3} 的 mex 是 0。
保证 1≤n≤106,0≤ai≤n。
题解
首先可以判断出,如果一个集合的mex为x的话,那么这个集合一定要包含1到x−1,而对于x
后面的数要不要都无所谓
所以我们可以先取出最大的mex,即最长的连续数+1
然后,考虑剩下的数。如果y能凑出来那么对于z<y,z一定能够凑出,所以想让z xor ans最大,从大向小考虑,如果z&ans=0,那么就选出1到z−1。
考场上就与没想出来,-30points
QAQ
代码
实现的不好,应该是O(n2)的,实际可以做到O(n)(但由于数据太水n方能过去)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include<bits/stdc++.h>
using namespace std;
int read() { int f = 1, x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = 10 * x + ch - '0'; ch = getchar(); } return f * x; }
const int N = 1e6 + 10; int a[N], n; int cnt[N]; int maxa = -1;
long long ans; int main() { freopen("mexor.in", "r", stdin); freopen("mexor.out", "w", stdout); n = read();
for(int i = 1;i <= n;i++) { a[i] = read(); cnt[a[i]]++; maxa = max(maxa, a[i]); } while(1) { int i = -1; for(;i <= maxa;i++) { if(cnt[i + 1] == 0) { break; } } if(i == -1) break; if((ans & (i + 1)) == 0) { ans += i + 1; for(int j = 0;j <= maxa;j++) { cnt[j] --; } } else { cnt[i] = 0; } }
printf("%lld", ans);
return 0; }
|