ABC249G Xor Cards 题解
题目描述
给定 \(n\) 张卡片,第 \(i\) 张卡片正面 \(a_i\) ,反面 \(b_i\) 。
你可以选择若干张卡片,要求正面异或和 \(\le k\) ,求反面异或和最大值。
如果你无法选择任何卡片,输出 -1 。
数据范围
- \(1\le n\le 1000,0\le k,a_i,b_i\lt 2^{30}\) 。
时间限制 \(\texttt{2s}\) ,空间限制 \(\texttt{1024MB}\) 。
分析
令 \(x_i=2^{30}\cdot a_i+b_i\) ,要求选择若干 \(x_i\) ,在满足前 \(30\) 位异或和 \(\le k\) 的前提下,求后 \(30\) 位异或和的最大值。
容易发现将 \(x_i\) 替换成 \(x_i\oplus x_j\) 对答案没有影响,因此可以先把 \(x_i\) 都插入到线性基中。
用另一个线性基存储所有可以随意选的 \(b_i\) 。
如果插入 \(x_i\) 的过程走到后 \(30\) 位,我们可以直接把当前 \(b_i\) 插入这个线性基。
先消成上三角基,统计答案时枚举每一位,假设因为没选 \(a_i\) 所以没有顶住 \(k\) 的上界。
高位的限制相当于钦定若干个数必选。在线性基中选若干个数与 \(x\) 的异或最大值是线性基的经典问题,直接按位贪心即可。
实现细节:
- 由于答案可能为 \(0\) ,所以不能想当然拿答案为 \(0\) 判无解,最简单的判断方法是看 \(a_i\) 的异或最小值是否 \(\le k\) 。
- 卡位没有判断 \(a_i\) 异或和恰好等于 \(k\) 的情况,记得特判。
时间复杂度 \(\mathcal O(n\log V+\log^3V)\) 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1005,all=(1<<30)-1;
int k,n,flg,res;
int a[maxn],b[maxn],v[maxn];
struct basis
{
int v[30];
void insert(int x)
{
for(int i=29;i>=0;i--)
{
if(!(x>>i&1)) continue;
if(!v[i]) return v[i]=x,void();
x^=v[i];
}
}
int query(int x)
{
for(int i=29;i>=0;i--) x=max(x,x^v[i]);
return x;
}
}now;
void insert(int x)
{
for(int i=59;i>=30;i--)
{
if(!(x>>i&1)) continue;
if(!v[i]) return v[i]=x,void();
x^=v[i];
}
flg=1,now.insert(x);
}
signed main()
{
scanf("%lld%lld",&n,&k),k<<=30;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i],&b[i]);
insert((a[i]<<30)|b[i]);
}
res=now.query(0);
for(int i=30;i<=59;i++)
for(int j=30;j<i;j++)
if(v[i]>>j&1) v[i]^=v[j];
for(int i=30;i<=59;i++) flg|=v[i]&&k>=(v[i]&~all);
if(!flg) printf("-1"),exit(0);
int tmp=0;
for(int i=30;i<=59;i++) if(k>>i&1) tmp|=v[i];
if(k==(tmp&~all)) res=max(res,tmp&all);
for(int i=59;i>=30;i--)
{
if(!(k>>i&1)) continue;
int cur=0;
for(int j=i+1;j<=59;j++) if(k>>j&1) cur^=v[j];
if((cur&~all)>k) break;
auto tmp=now;
for(int j=30;j<=i-1;j++) tmp.insert(v[j]&all);
res=max(res,tmp.query(cur&all));
}
printf("%lld\n",res);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16338873.html
浙公网安备 33010602011771号