4245: [ONTAK2015]OR-XOR
Description
给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。
Input
第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
第一行包含n个整数,其中第i个数为a[i] (0<=a[i]<=10^18)。
Output
输出一个整数,即总费用的最小值。
从最高位贪心,判断每一位时加上高位的限制(某些位是否全为\(0\))即可;
因为段内是异或运算,所以两个满足限制的段合并后仍满足限制;
然后就变成了判断每一位能否分成不少于\(m\)个满足限制且这一位异或和为\(0\)的段;
AC GET☆DAZE
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 500039
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,cnt;
ll num[N],now,ans;
int main()
{
scanf("%d%d",&n,&m);
for(int a=1;a<=n;a++)
{
scanf("%lld",&num[a]);
}
for(int a=60;~a;a--)
{
cnt=now=0;
for(int b=1;b<=n;b++)
{
now^=num[b];
if((now>>(a+1)<<(a+1)|ans)==ans && !(now>>a&1))
{
cnt++,now=0;
}
}
if(cnt<m || now) ans|=(1ll<<a);
}
printf("%lld",ans);
return 0;
}