题解:P17731 [ICPC 2019 Xuzhou R] Cat

· · 题解

题意

区间 [l,r] 选取一个区间 [a,b],满足 a \oplus (a+1) \oplus \cdots \oplus (b-1) \oplus b \le s 并且最大化 b-a+1。

题解

观察到一个性质,若 x 为偶数,则有 x \oplus (x+1) \oplus (x+2) \oplus (x+3) = 0。

:::info[证明]

容易观察到这样的性质:$x \oplus (x+1) = 1$,原因在于他们只有最低位不同。 这样两个 $1$ 异或得到 $0$。 ::: 因此,$[x,x+4k-1]$($x$ 为偶数)的异或值为 $0$,且是一个连续段。因此,选择这一段一定不劣,此时只需要向左向右暴力扩展即可。 写法上,这里提供一个特判较少的写法:如果 $r-l+1 \le 8$ 直接暴力查询,否则根据 $l$ 奇偶讨论,处理 $l,l+2/l+1,l+3$。这样只有左右端点发生变化,且没有越界风险。 ## 复杂度分析 处理完一个极长的连续段后,左右不可能出现一个长度超过 $3$ 的连续段,此时暴力就是 $O(1)$。(虽然说我写的常数有 $9$ 甚至 $512$ 吧,但还是 $O(1)$)。 ## 代码 ```cpp #include<bits/stdc++.h> using namespace std; #define ll long long inline ll rare(ll l, ll r, ll s){ ll ans = -1; for(ll i = l; i <= r; i++){ for(ll j = i; j <= r; j++){ ll sum = 0; for(ll k = i; k <= j; k++) sum ^= k; if(sum <= s) ans = max(ans, j - i + 1); } } return ans; } inline ll solve(ll l, ll r, ll tmpl, ll tmpr, ll s){ ll ans = -1, xorl = 0; for(ll i = tmpl; i >= l; i--){ if(i != tmpl) xorl ^= i; ll xorr = 0; for(ll j = tmpr; j <= r; j++){ if(j != tmpr) xorr ^= j; if((xorl ^ xorr) <= s) ans = max(ans, j - i + 1); } } return ans; } int ans; int main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); ll _, l, r, s; cin >> _; while(_--){ cin >> l >> r >> s; if(r - l + 1 <= 8){ cout << rare(l, r, s) << "\n"; continue; } if(l & 1){ ll tmpl = l + 1, tmpr = tmpl + (r - tmpl + 1) / 4 * 4 - 1, ans = -1; ans = max(ans, solve(l, r, tmpl, tmpr, s)); tmpl = l + 3, tmpr = tmpl + (r - tmpl + 1) / 4 * 4 - 1; ans = max(ans, solve(l, r, tmpl, tmpr, s)); cout << ans << "\n"; }else{ ll tmpl = l, tmpr = tmpl + (r - tmpl + 1) / 4 * 4 - 1, ans = -1; ans = max(ans, solve(l, r, tmpl, tmpr, s)); tmpl = l + 2, tmpr = tmpl + (r - tmpl + 1) / 4 * 4 - 1; ans = max(ans, solve(l, r, tmpl, tmpr, s)); cout << ans << "\n"; } } return 0; } ```