题解:CF1863F Divide, XOR, and Conquer
题目传送门:CF1863F
定义
-
-
区间
[l, r] 合法当且仅当它可以由[1, n] 缩小得来。 -
解题
想一下在大区间
是
试比较
从二进制考虑。假如
特殊情况:
因此,选择左边区间
选右边区间同理。
用区间dp,从大区间往小推。对于每个小区间
可以把所有以
这样,转移方程如下,其中布尔值
由于区间长度从大往小算,
但是要注意判断
#include<bits/stdc++.h>
using namespace std;
#define ofor(i, a, b) for (register int i = a; i < b; i++)
#define cfor(i, a, b) for (register int i = a; i <= b; i++)
#define bfor(i, a, b) for (register int i = a; i >= b; i--)
#define set0(a) memset(a, 0, sizeof(a));
#define X 10005
typedef long long ll;
int T, n;
ll a[X];
ll sum[X]; // 异或前缀和
ll hl[X], hr[X];
// hl[l]是二进制数,其中从右往左第d位上的数,表示:
// 所有以l为左端点的区间中,有/没有一个合法区间的异或和的最高位为d。
// hr[r]表示所有以r为右端点的区间中,……
bool anyl[X], anyr[X]; // anyl[l] = 1,表示任何以l为左端点的区间都能取
inline ll highbit(ll x) {
return 1ll << (63 - __builtin_clzll(x)); // 内置函数
}
inline ll xor_sum(int l,int r) {
return sum[r] ^ sum[l - 1];
}
int main() {
cin >> T;
while (T--) {
set0(hl);
set0(hr);
set0(anyl);
set0(anyr);
cin >> n;
cfor (i, 1, n) cin >> a[i];
cfor (i, 1, n) sum[i] = sum[i - 1] ^ a[i];
int r;
ll xs;
bool f;
bfor (len, n, 1) {
cfor (l, 1, n - len + 1) {
r = l + len - 1;
xs = xor_sum(l, r);
f = (xs & hl[l]) or (xs & hr[r]);
if (anyl[l] or anyr[r]) f = true;
if (len == n) f = true;
if (len == 1) cout << f;
// 区间dp,f表示区间[l, r]是否合法,不需要用数组存
if (f) {
hl[l] |= highbit(xs), hr[r] |= highbit(xs);
if (xs == 0) anyl[l] = anyr[r] = true; // 如果异或和为0,那么选左边右边都可以
}
}
}
cout << endl;
}
return 0;
}