题解:P8569 [JRKSJ R6] 第七学区
一些记号与约定
我们约定二进制表示下最低位为第 \(0\) 位,设 \(\operatorname{bit}_i(x)\) 为 \(x\) 在二进制表示下第 \(i\) 位的值。
题意
给定长度为 \(n\) 的序列 \(a\),求其所有子区间的按位或和之和,答案对 \(2^{64}\) 取模。\(1\leq n\leq 5\times 10^7\),\(0\leq a_i<2^{64}\)。
题解
神题。
容易得到一个 \(\mathcal{O}(n\log{V})\) 的做法。拆位,对于某一个位 \(i\),一个区间在该位上有贡献当且仅当其中存在 \(1\)。考虑从小到大右端点 \(i\),设 \(f_{j}\) 为 \(a_{1\sim i}\) 在第 \(j\) 位中最后一个 \(1\) 的位置。每次加入一个 \(a_i\) 时,若 \(\operatorname{bit}_j(a_i)=1\),则令 \(f_j\gets i\),否则不变。每个 \(i\) 会对答案贡献 \(2^i\sum\limits_{j=0}^{\log{V}}f_j\)。
考虑优化。这里使用一个很牛的 trick:注意到我们的转移在维护 \(f\) 时相当于维护了 \(\log{V}\) 个 \(\leq n\) 的数,考虑把 \(f\) 视作一个 \(\log{V}\times \log{n}\) 的 \(0/1\) 矩阵,那么我们将这个矩阵转置,改为维护 \(\log{n}\) 个 word。具体来说,维护 \(\log{n}\) 个 word \(g_i\),表示有哪些 \(j\) 使得 \(\operatorname{bit}_i(f_j)=1\)。
考虑原来 \(f\) 的变化怎么放到 \(g\) 上。考察一个位 \(j\) 使得 \(\operatorname{bit}_j(a_i)=1\),对于每个 \(k\),我们需要把 \(g_k\) 的第 \(j\) 位设为 \(\operatorname{bit}_j(i)\)。不难看出这相当于:枚举 \(k\),若 \(\operatorname{bit}_k(i)=1\),则令 \(g_k\gets g_k\operatorname{or} a_i\),否则令 \(g_k\gets g_k\operatorname{and} \lnot a_i\)。此时每个 \(i\) 对答案贡献 \(\sum\limits_{j=0}^{\log{n}}2^jg_j\)。
按照上述过程直接做即可,时间复杂度 \(\mathcal{O}(n\log{n})\)。
代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x) & -(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const int N = 5e7 + 5, B = 26;
template<typename T> inline void chk_min(T &x, T y) { x = min(x, y); }
template<typename T> inline void chk_max(T &x, T y) { x = max(x, y); }
namespace IO {
const int S = 1 << 24, lm = 1 << 23;
char bi[S + 5], *p1 = bi, *p2 = bi, ch;
#define gc() (p1 == p2 && (p2 = (p1 = bi) + fread(bi, 1, 1 << 23, stdin), p1 == p2) ? EOF : *p1++)
inline ull rd() {
char ch;
while (ch = gc(), (ch < '0'));
ull x = ch ^ 48;
while (ch = gc(), (ch >= '0')) x = (x << 3) + (x << 1) + (ch ^ 48);
return x;
}
}
using IO::rd;
namespace Read {
int l, r;
ull tp[10005], g1, g2;
void init(int &n) {
n = rd(), l = 1; int k = rd();
for (int i = 1; i <= k; ++i) tp[i] = rd();
}
ull read() {
if (l > r) l = rd(), r = rd(), g1 = rd(), g2 = rd();
return tp[l++] * g1 + g2;
}
}
int n;
ull ans, b[B];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
Read::init(n);
for (int i = 1; i <= n; ++i) {
ull x = Read::read();
for (int j = 0; j < B; ++j) ans += (i >> j & 1 ? b[j] |= x : b[j] &= ~x) << j;
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号