题目描述
小H是一个热爱出毒瘤题的女孩子。
小H按照老师要求出了一道搜索题。这是一道只有题目和搜索有关的题目。
现在你有一个长度为n的数列A,每个数为ai,你要将它分成m段,每段至少1个数。令每段的异或值为ci。
你需要最小化所有ci或起来的值。
题解
显然我们希望高位为0,那么我们就一位一位贪心下去。如果在保证之前的高位切得动的情况下,能切就切下去,如果能切出大于等于m块即可,因为任意几块合起来还是偶的。
介绍一个巧妙的代码实现。我们可以随时记着当前的答案,如果这个区间和答案与起来还是等于这个区间相当于这个区间上不存在不在答案上的1,有的话就被消了。
代码
#include <bits/stdc++.h>
#define maxn 500005
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
LL read(){
LL res,f=1; char c;
while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48);
while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
return res*f;
}
LL n,m,a[maxn],sum[maxn],ans;
bool check(){
int num=0,lst=0;
for(int i=1;i<=n;i++){
if(((sum[i]^sum[lst])&ans)==(sum[i]^sum[lst])) num++,lst=i;
}
return num<m||lst^n;
}
int main(){
n=read(); m=read();
for(int i=1;i<=n;i++) sum[i]=sum[i-1]^read();
ans=(1ll<<61)-1;
for(int s=60;~s;s--){
ans^=(1ll<<s);
if(check()) ans|=(1ll<<s);
}
printf("%lld\n",ans);
}