bzoj4245 [ONTAK2015]OR-XOR (贪心)

4245: [ONTAK2015]OR-XOR

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 856 Solved: 469
[Submit][Status][Discuss]
## 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;
}
posted @ 2018-05-31 08:43  Sinogi  阅读(150)  评论(0编辑  收藏  举报