#include<bits/stdc++.h>
#define ll long long
#define all(a) (a).begin(),(a).end()
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
/*
链接 : https://codeforces.com/gym/104369/problem/G
题意 : 求 F(A) = max((a[1] & a[2] & ... & a[k]) + (a[k + 1] & a[k + 2] & ... & a[n]))
最多可以进行一次交换 a 中两个元素的位置
分析 :令 f(i, j) 表示 a[i] & a[i + 1] & ... & a[j]
假设 k 固定,对于前缀 f(1, k) 中至多有 log 个关键点 i 使得 f(1, i - 1) != f(1, i)
对于后缀 f(k + 1, n) 也至多有 log 个位置 j 使得 f(j + 1, n) != f(j, n)
假设交换了两个非关键点,因为移走非关键点后值不会发生改变,
加入另一个非关键点还可能导致整体值变小,所以这样的交换是没有意义的
假设交换了两个关键点,因为前后缀关键点都至多 log 个,暴力枚举 k 和前后缀关键点即可,复杂度 O(nlog^2)
假设交换了一个关键点和一个非关键点,以前缀关键点 i 和后缀非关键点 j 为例
后缀的值为 f(k + 1, n) & a[i] 也就是说如果 a[i] 确定,则 后缀的值也确定
此时只需要找出一个非关键点 j 使得 f(1, i - 1) & a[j] & f(i + 1, k) 最大即可
f(i + 1, k) 的值只有 log 种,对于 f(i + 1, k),若 i 固定,则 k 越小越好,因为 k 越小可以选择的 j 越多
所以只需要暴力枚举 i 和 k,对于新的值 f(i + 1, k) 再暴力枚举 j 即可,复杂度 O(nlog^2)
*/
int n, a[N];
int f[21][N], Log[N];
void init_ST()
{
for(int i = 1; i <= n; i++) f[0][i] = a[i];
for (int j = 1; j <= 20; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
f[j][i] = (f[j - 1][i] & f[j - 1][i + (1 << (j - 1))]);
Log[1] = 0;
for (int i = 2; i <= n; i++)
Log[i] = Log[i / 2] + 1;
}
int query(int l, int r)
{
if(l > r) return (1 << 30) - 1;
int k = Log[r - l + 1];
return f[k][l] & f[k][r - (1 << k) + 1];
}
int ans;
map<array<int, 2>, int> vis;
void cal_pre(int i, int val, int suf_val, int k)
{
if(vis.count({val, i})) return;
vis[{val, i}] = 1;
int mx = 0;
for(int j = k + 1; j <= n; j++) mx = max(mx, val & a[j]);
ans = max(ans, mx + suf_val);
}
void cal_suf(int j, int val, int pre_val, int k)
{
if(vis.count({j, val})) return;
vis[{j, val}] = 1;
int mx = 0;
for(int i = 1; i <= k; i++) mx = max(mx, val & a[i]);
ans = max(ans, pre_val + mx);
}
void solve()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
init_ST();
ans = 0;
for(int k = 1; k < n; k++) ans = max(ans, query(1, k) + query(k + 1, n));
vector<int> pre, suf;
for(int i = 1; i < n; i++) if(query(1, i - 1) != query(1, i)) pre.push_back(i);
for(int i = n; i > 1; i--) if(query(i + 1, n) != query(i, n)) suf.push_back(i);
for(int k = 1; k < n; k++)
{
for(auto &i : pre)
{
if(i > k) break;
for(auto &j : suf)
{
if(j <= k) break;
int res1 = (query(1, i - 1) & a[j] & query(i + 1, k));
int res2 = (query(k + 1, j - 1) & a[i] & query(j + 1, n));
ans = max(ans, res1 + res2);
}
}
}
pre.clear();
for(int k = 1; k < n; k++)
{
if(query(1, k - 1) != query(1, k)) pre.push_back(k);
for(auto &i : pre) cal_pre(i, query(1, i - 1) & query(i + 1, k), query(k + 1, n) & a[i], k);
}
vis.clear();
suf.clear();
for(int k = n - 1; k >= 1; k--)
{
if(query(k + 1, n) != query(k + 2, n)) suf.push_back(k + 1);
for(auto &j : pre) cal_suf(j, query(k + 1, j - 1) & query(j + 1, n), query(1, k) & a[j], k);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--) solve();
return 0;
}
广东省赛G. Swapping Operation
于 2023-06-22 13:59:56 首次发布