BZOJ 4017: 小Q的无敌异或

对于位运算的题目,大多需要按位计算
对于第一问,按位考虑,即对于每个右端点,查询有多少个左端点在该位下与其不同,\(O(n)\) 扫一遍即可
对于第二问,同样按位考虑
对于每一位,只有奇数对 \(sum(l,r)\) 在该位下为 \(1\) 时才能对答案有贡献
即要满足 \(sum_{r} - sum_{l-1} \bmod 2^{k+1} \geq 2^k\)
先将所有 \(sum\)\(2^{k+1}\) 取模
有两种情况

  1. \(sum_{r}-sum_{l-1} \geq 2^k \wedge sum_r > sum_{l-1}\)
  2. \(sum_{r} + 2^k \geq sum_{l-1} \wedge sum_{l-1}> sum_{r}\)
    分别用树状数组统计一下即可
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define SZ(x) ((int)(x).size())
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=((b)-1);i>=(a);i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 998244353, INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1e5 + 7;
int a[N];
ll sum[N];
int n, cnt;
ll v[N];
int getid(ll x) {
	return std::upper_bound(v + 1, v + cnt + 1, x) - v - 1;
}

struct BIT {
	int tree[N];
	void init() {
		rep (i, 0, cnt + 3) tree[i] = 0;
	}
	void modify(int x) {
		for (int i = x; i <= cnt; i += lowbit(i)) tree[i] ^= 1;
	}
	int query(int x) {
		int ans = 0;
		for (int i = x; i; i -= lowbit(i)) ans ^= tree[i];
		return ans;
	}
} bit;

int main() {
#ifdef LOCAL
	freopen("ans.out", "w", stdout);
#endif
	n = _();
	int mx = 0;
	rep (i, 1, n + 1) {
		a[i] = _();
		sum[i] = sum[i - 1] ^ a[i];
		chkmax(mx, int(sum[i]));
	}
	int ans = 0;
	for (int k = 0; (1ll << k) <= mx; k++) {
		static int cnt[3];
		cnt[0] = 1; cnt[1] = 0;
		rep (i, 1, n + 1) {
			int d = sum[i] >> k & 1;
			M(ans += (1ll << k) * cnt[d ^ 1] % MOD);
			cnt[d]++;
		}
	}
	printf("%d ", ans);
	ll res = 0;
	rep (i, 1, n + 1) sum[i] = sum[i - 1] + a[i];
	for (int k = 0; (1ll << k) <= sum[n]; k++) {
		rep (i, 0, n + 1) v[i + 1] = sum[i] & ((1ll << (k + 1)) - 1);
		std::sort(v + 1, v + n + 2);
		cnt = std::unique(v + 1, v + n + 2) - v - 1;
		bit.init();
		int temp = 0;
		rep (i, 0, n + 1) {
			ll cur = sum[i] & ((1ll << (k + 1)) - 1);
			temp ^= bit.query(getid(cur - (1ll << k))) ^ bit.query(getid(cur)) ^ bit.query(getid(cur + (1ll << k)));	
			bit.modify(getid(cur));
		}
		if (temp) res |= 1ll << k;
	}
	printf("%lld\n", res);
#ifdef LOCAL
	printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}
posted @ 2020-03-12 21:26  Mrzdtz220  阅读(101)  评论(0编辑  收藏  举报