一个不太复杂的做法。
首先我们可以考虑将每一段区间拆成 \(\log V\) 级别的形如 \([p,p+2^q)\) 个段,其实就是可以理解为一段前缀加上一段自由段,然后我们考虑将 \(A,B\) 进行合并合并完之后的每一段也是长成刚刚那样,但是这样子合并我们得到的段有 \(\mathcal{O}(n^2\log^2V)\) 个级别的段,无法通过。
合并时我们产生了很多的空间浪费。观察到在合并 \([p_A,p_A+2^{q_A})\) 和 \([p_B,p_B+2^{q_B})\) 两段时,只有满足 \(p_A=p_B\),或 \(\min(p_A,p_B)=0\) 时,这个合并才是有意义的,为什么呢?
观察拆段时的过程,每当我们在加入一个区间后,我们会改变一下当前的位并往后继续加入新的区间,这提醒我们,在 \(q_A,q_B\) 都大于零的时候,\(\left|q_A-q_B\right|\ge1\) 时我们的合并是无意义的。因为我们显然可以让自由段更短的段继续缩减自由段并与自由段较长的合并,所以这样子我们得到的答案段数量级只有 \(\mathcal{O}(n^2\log V)\) 级别了。
但是我们最后还需要去重,观察到这些段显然要么包含要么不交,所以直接排序然后去重即可,常数不是很大就可以通过。
代码:
#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define eb emplace_back
#define inf 1000000000
#define linf 100000000000000
#define pii pair <int, short>
using namespace std;
constexpr int N = 2e5 + 5, P = 998244353;
inline int rd ()
{
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) { if (ch == '-') f = -1; ch = getchar (); }
while (isdigit (ch)) { x = (x << 1) + (x << 3) + ch - 48; ch = getchar (); }
return x * f;
}
int n, m;
vector <pii> v1, v2, v3;
signed main ()
{
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
n = rd ();
rep (t, 1, n)
{
int l = rd (), r = rd ();
if (l == r)
{
v1.eb (pii (l, 0));
continue;
}
int x = 0, d;
rrp (j, 0, 60)
{
int bl = l >> j & 1, br = r >> j & 1;
if (bl == br) d = j;
else break;
x |= bl; x <<= 1;
}
int y = x;
y |= 1; y <<= 1;
rrp (j, 0, d - 2)
{
int b = r >> j & 1;
if (b) v1.eb (pii (y, j));
y |= b; y <<= 1;
}
v1.eb (pii (y >> 1, 0));
y = x; y <<= 1;
rrp (j, 0, d - 2)
{
int a = l >> j & 1;
if (! a) v1.eb (pii (y | 1, j));
y |= a; y <<= 1;
}
v1.eb (pii (y >> 1, 0));
}
m = rd ();
rep (t, 1, m)
{
int l = rd (), r = rd ();
if (l == r)
{
v2.eb (pii (l, 0));
continue;
}
int x = 0, d;
rrp (j, 0, 60)
{
int bl = l >> j & 1, br = r >> j & 1;
if (bl == br) d = j;
else break;
x |= bl; x <<= 1;
}
int y = x;
y |= 1; y <<= 1;
rrp (j, 0, d - 2)
{
int b = r >> j & 1;
if (b) v2.eb (pii (y, j));
y |= b; y <<= 1;
}
v2.eb (pii (y >> 1, 0));
y = x; y <<= 1;
rrp (j, 0, d - 2)
{
int a = l >> j & 1;
if (! a) v2.eb (pii (y | 1, j));
y |= a; y <<= 1;
}
v2.eb (pii (y >> 1, 0));
}
for (auto u : v1)
{
for (auto v : v2)
{
int x = u.first, y = u.second, xx = v.first, yy = v.second;
if (y > yy) swap (y, yy), swap (x, xx);
if (! y || yy == y)
{
int g = ((x << y) ^ (xx << yy)) >> yy << yy;
v3.eb (pii (g, - yy));
}
}
}
sort (v3.begin (), v3.end ());
int ans = 0, cnt = 0;
int w = -1;
for (int i = 0; i < v3.size (); ++ i)
{
int p = v3[i].first, q = - v3[i].second;
if (w >= p) continue;
w = p + (1ll << q) - 1; ++ cnt;
int x = 1ll << q;
(ans += x % P * (p % P) % P + ((x >> 1) % P) * ((x - 1) % P) % P) %= P;
}
printf ("%lld\n", ans);
}
/*
*/
标签:pii,Set,Xor,int,eb,rd,bl,CF1261F,define
From: https://www.cnblogs.com/lalaouyehome/p/18302147