搜索题
题目描述
小H是一个热爱出毒瘤题的女孩子。
小H按照老师要求出了一道搜索题。这是一道只有题目和搜索有关的题目。
现在你有一个长度为n的数列A,每个数为ai,你要将它分成m段,每段至少1个数。令每段的异或值为ci。
你需要最小化所有ci或起来的值。
【数据范围】 1≤m≤n≤5*10^5,0≤ai≤10^18
solution
考虑从高位开始贪心
如果这一位出现了奇数个一,那么这一位就应该是不合法的,可以跳过
如果是偶数个,那么我们可以贪心判断。
那么怎么在保证之前合法的时候寻找当下合法的的方案呢
我开了个变量M 表示第i位是否能做到合法,如果能就为1
如果当前所有为的异或和为t,且t&m==0 则当前位为一个合法的划分
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define maxn 500005
using namespace std;
int n,m,tot;
ll a[maxn],flag,Max,ans,M;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
Max=max(Max,a[i]);
}
int bs;
for(bs=0;(ll)(1LL<<bs)<=Max;bs++);M=0;
for(int ws=bs;ws>=0;ws--){
int num=0;
for(int i=1;i<=n;i++)
if(a[i]&((ll)(1LL<<ws)))num++;
if(num%2==0){
M+=(ll)(1LL<<ws);
int cnt=0;ll t=0;
for(int i=1;i<=n;i++){
t=t^a[i];
if((t&M)==0)cnt++,t=0;
if(cnt==m)break;
}
if(cnt!=m)ans+=(ll)(1LL<<ws),M-=(ll)(1LL<<ws),tot--;
}
else ans+=(ll)(1LL<<ws);
}
cout<<ans<<endl;
return 0;
}