时限:2s
空限:256MB
这题非常容易想到先做个前缀和
(a,b,c)分别表示三个人的粉丝数
不妨变成(a-b,a-c,b-c)
这样相当于要从前面的前缀中选个三维都不一样的,使异或和最大。
那么这个可以暴力容斥地建出八种trie(每一维选和不选),然后自高位到低位的贪心,有的话走过去即可。
注意如果有两维相同第三维也一定相同,所以优化到5种trie
复杂度 O ( n l o g ∣ V ∣ ∗ 5 ) O(nlog|V|*5) O(nlog∣V∣∗5),可惜trie的空间有点大,不行
劳动人民的智慧是无穷的,我们开发trie上动态缩边技巧,反正最后缩出来的点数就是虚树的点数,上限是2n,有一点难打,可以看代码。
题解利用到了几个性质:
1是之前说到的要么一维相同要么三维相同。
2是我们只要判定是否存在而不用求个数。
于是我们先随便记一个(a,b,c)
假设来了(x,y,z)
若完全相等,则记是否存在三维与(a,b,c)不同的即可。
考虑有一维相同,假设就是a=x
记一个(a’,b’,c’)满足a’不等于a
再比较,若此时还有一维相同假设b’=y
再记(a’’,b’’,c’’)满足a’‘≠a,b’‘≠b’
若还不满足,再记(a’’’,b’’’,c’’’)满足a’’‘≠a,b’’‘≠b’,c’’‘≠c’’
其实就是几个二进制状态表示这些数是否存在,似乎有点烦。
我的代码是优化trie的:
#include
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define db double
#define ll long long
#define pp printf
using namespace std;
const int N = 3e5 + 5;
int n, opt;
int a[N], b[N];
int ans[N];
const int M = 3e6;
int son[M][2], tot, siz[M], len[M], t[M];
map<ll, int> rt[5];
const int C = 200005;
ll z2(ll x, ll y) {
return (x + 1e5) * C + (y + 1e5);
}
int s[N][3];
int f[5] = {1, -1, -1, -1, 2};
int mk;
int W;
int fz(int x) {
int y = 0;
fo(i, 0, 29) y += (1 << (29 - i)) * (x >> i & 1);
return y;
}
void split(int x, int c, int l) {
int y = son[x][c];
if(l == len[y]) return;
len[++ tot] = l;
t[tot] = t[y] & ((1 << l) - 1);
siz[tot] = siz[y];
t[y] >>= l; len[y] -= l;
son[x][c] = tot; son[tot][t[y] & 1] = y;
}
#define qw(x, y) ((x) >> (y) & 1)
void dd(int &rt) {
if(!rt) rt = ++ tot;
int x = rt, T = W, L = 30;
while(1) {
int c = T & 1;
int y = son[x][c], lp = 0;
while(lp < len[y] && qw(t[y], lp) == qw(T, lp)) lp ++;
if(!lp) break;
split(x, c, lp);
T >>= lp; L -= lp;
x = son[x][c]; siz[x] ++;
}
if(L > 0) {
int c = T & 1;
t[++ tot] = T, len[tot] = L;
son[x][c] = tot;
siz[tot] ++;
}
}
void ad(int i) {
W = fz(W);
dd(rt[0][0]);
dd(rt[1][s[i][0]]); dd(rt[2][s[i][1]]); dd(rt[3][s[i][2]]);
dd(rt[4][z2(s[i][0], s[i][1])]);
}
struct wz {
int x, l;
} w[5];
int nsiz(wz w, int c) {
if(w.l == len[w.x]) return siz[son[w.x][c]];
return qw(t[w.x], w.l) == c ? siz[w.x] : 0;
}
void move(wz &w, int c) {
if(w.l == len[w.x]) w.l = 1, w.x = son[w.x][c]; else {
if(qw(t[w.x], w.l) == c) w.l ++; else
w.x = 0;
}
}
int main() {
freopen("imbalance.in", "r", stdin);
freopen("imbalance.out", "w", stdout);
scanf("%d %d", &n, &opt);
fo(i, 1, n) scanf("%d", &a[i]);
fo(i, 1, n) scanf("%d", &b[i]);
ad(0);
fo(i, 1, n) {
if(opt) {
a[i] = (a[i] ^ ans[i - 1]) % 3;
b[i] = b[i] ^ ans[i - 1];
}
b[i] ^= b[i - 1];
fo(j, 0, 2) s[i][j] = s[i - 1][j];
if(a[i] == 0) {
s[i][0] ++; s[i][1] ++;
}
if(a[i] == 1) {
s[i][0] --; s[i][2] ++;
}
if(a[i] == 2) {
s[i][1] --; s[i][2] --;
}
w[0].x = rt[0][0];
w[1].x = rt[1][s[i][0]]; w[2].x = rt[2][s[i][1]]; w[3].x = rt[3][s[i][2]];
w[4].x = rt[4][z2(s[i][0], s[i][1])];
fo(j, 0, 4) w[j].l = 0;
fd(j, 29, 0) {
int c = b[i] >> j & 1;
int s = 0;
fo(k, 0, 4) {
s += f[k] * nsiz(w[k], c ^ 1);
}
if(s) {
ans[i] += 1 << j;
fo(k, 0, 4) move(w[k], c ^ 1);
} else {
fo(k, 0, 4) move(w[k], c);
}
}
W = b[i]; ad(i);
}
fo(i, 1, n) pp("%d ", ans[i]);
}