博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj4245】[ONTAK2015]OR-XOR 贪心
阅读量:4497 次
发布时间:2019-06-08

本文共 1319 字,大约阅读时间需要 4 分钟。

题目描述

给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。

输入

第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
第一行包含n个整数,其中第i个数为a[i](0<=a[i]<=10^18)。

输出

输出一个整数,即总费用的最小值。

样例输入

3 2

1 5 7

样例输出

3


题解

贪心

还是那句话:100000(2)>011111(2)

所以想让总数最小,应该尽量让高位为0。

而如果a or b or c or ... = 0,则一定是a、b、c、...都等于0。

于是就转化为让某一段的xor为0.

考虑xor的性质,a xor a = 0。

根据这个性质可以使用前缀和处理这种xor问题。

具体的,xor(i,j)=xor(1,i-1)^xor(1,i-1)^xor(i,j)=sum[i-1]^sum[j]。

而题目要求需要分出m段,所以某一位为0的充分必要条件是sum[n]=0,且满足sum[i]=0&&tag[i]=0(见下行)的i的个数>=m。

这样能够使得该位为0。而该位已经是0了,破坏条件的都不能选,所以应把sum[i]≠0的i打上标记,表示不能再选择。

最后被迫选的1的和就是答案。

#include 
#include
using namespace std;long long sum[500010] , x , ans;bool tag[500010];int main(){ int n , m , i , j; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &x) , sum[i] = sum[i - 1] ^ x; for(i = 62 ; ~i ; i -- ) { int num = 0; for(j = 1 ; j <= n ; j ++ ) if(!(sum[j] & (1ll << i)) && !tag[j]) num ++ ; if(sum[n] & (1ll << i) || num < m) ans += (1ll << i); else for(j = 1 ; j <= n ; j ++ ) if(sum[j] & (1ll << i)) tag[j] = 1; } printf("%lld" , ans); return 0;}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/6935154.html

你可能感兴趣的文章
shell笔记
查看>>
python的循环,质数和因子的定义
查看>>
Plan : 破晓
查看>>
JSON【介绍、语法、解析JSON】
查看>>
Xcode9出现错误safe area layout guide before ios 9 真正解决办法
查看>>
【Linux】zabbix_server自启动脚本
查看>>
GNU make
查看>>
Visual Studio 2008 不能更改安装目录的原因
查看>>
threejs学习笔记04---相机动
查看>>
SAP Skill - How to search a field for which table it belongs
查看>>
parcel+vue入门
查看>>
基数排序
查看>>
Dell笔记本刷回低版本bios的方法
查看>>
redis资料
查看>>
《自己动手写docker》之namespace部门实验
查看>>
Vim学习总结
查看>>
maven也是Apache开发的,也是java开发的。maven需要你本地系统JDK的支持
查看>>
垂直同步v-sync
查看>>
const关键字祥解
查看>>
JDK提供的并发工具类
查看>>