BZOJ4888 [Tjoi2017]異或和 【樹狀數組】
阿新 • • 發佈:2018-05-11
討論 樹狀數組 names php inline tps 前綴和 大於 似的 後面的數,為此時相減後該位為\(1\)的充要條件
題目鏈接
BZOJ4888
題解
要求所有連續異或和,轉化為任意兩個前綴和相減
要求最後的異或和,轉化為求每一位\(1\)的出現次數
所以我們只需要對每一個\(i\)快速求出\(sum[i] - sum[j] \quad [j < i]\)當前位的\(1\)的個數
顯然是將前\(i\)個數放到某一個數據結構中查詢
我的思路到這裏停住
兩個數相減,要第\(b\)位為\(1\),我們放到具體情境中觀察:
假若\(sum[i]\)的第\(b\)位為\(1\)
....1....
....?....
1、如果\(?=0\)
就是
....1....
....0....
發現\(1\)後面的數大於等於 \(0\)
2、如果\(?=1\)
就是
....1....
....1....
發現\(sum[i]\)的\(1\)後面的數小於\(sum[j]\)的\(1\)後面的數,為此時相減後該位為\(1\)的充要條件
如果第\(b\)位為\(0\)也是類似的討論
如果我們將該位為\(0\)和\(1\)的數分開討論,現在問題就轉化為了,如何快速求當前某一範圍內的數的個數
顯然就是對\(0\)和\(1\)分別開一個權值樹狀數組啦
題目中\(a[i]\)之和\(\le 10^6\)的條件也是一個明顯的暗示
這樣我們就\(O(20 * nlogS)\)做出這道題了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define lbt(x) (x & -x)
using namespace std;
const int maxn = 100005,maxm = 1000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int MX = 1000001;
struct BIT{
int s[maxm];
void clear(){cls(s);}
void add(int u){while (u <= MX) s[u]++,u += lbt(u);}
int query(int u){int re = 0; while (u) re += s[u],u -= lbt(u); return re;}
int sum(int l,int r){return query(r) - query(l - 1);}
}T0,T1;
int n,a[maxn],mx;
bool check(int b){
T0.clear(); T1.clear();
LL cnt = 0; int tmp;
for (int i = 0; i <= n; i++){
tmp = a[i] % b + 1;
if (a[i] & b){
cnt += T0.sum(1,tmp) + T1.sum(tmp + 1,MX);
T1.add(tmp);
}
else {
cnt += T0.sum(tmp + 1,MX) + T1.sum(1,tmp);
T0.add(tmp);
}
}
return cnt & 1;
}
int main(){
n = read(); int x,ans = 0;
REP(i,n) a[i] = a[i - 1] + (x = read()),mx = max(mx,a[i]);
for (int i = 0; mx; i++,mx >>= 1){
if (check(1 << i)) ans += (1 << i);
}
printf("%d\n",ans);
return 0;
}
BZOJ4888 [Tjoi2017]異或和 【樹狀數組】