题目链接
题意:给你一个数组,求它有多少个子区间所有数都出现了奇数次。$n \leqslant 2 \times 10^5$。
首先给每一个数$\text{rand}$一个权值,那么一个区间满足条件等价于这个区间所有数的权值异或和$\text{xor}$上这个区间去重后的所有数的权值异或和为$0$。
然后我们从左到右枚举区间的右端点,然后维护每个左端点的权值。我们定义$pre[i]$为上一个与位置$i$上的数相等的位置,那么右端点移到$i$时,左端点在$[1,pre[i]]$的所有区间的权值都会异或上位置$i$上的数的权值。
然后我们就是需要支持区间$\text{xor}$一个数,查询有多少个$0$。这个东西显然可以用分块解决。
复杂度$O(n\sqrt{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 70 71 72 73 74 75 76
| #include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 200000, maxv = 1000000, blksz = 500, mod = 100003; int n, pre[maxn + 10], lst[maxv + 10]; ull w[maxv + 10], val[maxn + 10], tag[maxn / blksz + 10], ans;
struct hshtb { int h[mod], cnt[blksz + 10], ccnt, nxt[blksz + 10]; ull val[blksz + 10];
void clear() { for (int i = 1; i <= ccnt; ++i) h[val[i] % mod] = 0; ccnt = 0; }
int& operator[] (ull v) { for (int i = h[v % mod]; i; i = nxt[i]) if (val[i] == v) return cnt[i]; val[++ccnt] = v; cnt[ccnt] = 0; nxt[ccnt] = h[v % mod]; h[v % mod] = ccnt; return cnt[ccnt]; }
int ask(ull v) { for (int i = h[v % mod]; i; i = nxt[i]) if (val[i] == v) return cnt[i]; return 0; } }mp[maxn / blksz + 10];
void modify(int p, ull v) { for (int i = 1; (i - 1) * blksz + 1 <= p; ++i) if (i * blksz <= p) tag[i] ^= v; else { for (int j = (i - 1) * blksz + 1; j <= i * blksz && j <= n; ++j) { val[j] ^= tag[i]; } tag[i] = 0; mp[i].clear(); for (int j = (i - 1) * blksz + 1; j <= i * blksz && j <= n; ++j) { if (j <= p) val[j] ^= v; ++mp[i][val[j]]; } } }
ull query(int p) { ull ans = 0; for (int i = 1; (i - 1) * blksz + 1 <= p; ++i) if (i * blksz <= p) ans += mp[i].ask(tag[i]); else for (int j = (i - 1) * blksz + 1; j <= p; ++j) ans += !(val[j] ^ tag[i]); return ans; }
int main() { w[0] = 131; for (int i = 1; i <= maxv; ++i) { w[i] = w[i - 1]; w[i] ^= w[i] << 13; w[i] ^= w[i] >> 17; w[i] ^= w[i] << 5; } scanf("%d", &n); for (int i = 1; i <= n; ++i) ++mp[(i - 1) / blksz + 1][0]; for (int i = 1; i <= n; ++i) { int x; scanf("%d", &x); pre[i] = lst[x]; lst[x] = i; modify(pre[i], w[x]); ans += query(i); } printf("%llu", ans); }
|