bzoj 4245 OR-XOR(按位异或贪心)
2016-05-23 16:46
369 查看
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4245
题意:求n个数分成连续m段,每段取异或最后所有段或值的最小值
题解:经过这几道异或的题目,找到了一点套路,就是异或一般来说,找连续的一段和什么的异或最大值,就是异或字典树。像前一题两个区间内找异或最大值,或者这题找异或之后或值最大,就是应该按位异或贪心。
先求处前缀异或,然后按位枚举,如果这一位上,有大于等于m个没有被标记前缀为0,并且第n位必须为0(最后一段),然后答案的这一位即可以取0,说明按照这么分割,贪心的让解最小,所以此时要把这一位上前缀异或是1的都标记,否则就是这一位必须取1.
代码:
题意:求n个数分成连续m段,每段取异或最后所有段或值的最小值
题解:经过这几道异或的题目,找到了一点套路,就是异或一般来说,找连续的一段和什么的异或最大值,就是异或字典树。像前一题两个区间内找异或最大值,或者这题找异或之后或值最大,就是应该按位异或贪心。
先求处前缀异或,然后按位枚举,如果这一位上,有大于等于m个没有被标记前缀为0,并且第n位必须为0(最后一段),然后答案的这一位即可以取0,说明按照这么分割,贪心的让解最小,所以此时要把这一位上前缀异或是1的都标记,否则就是这一位必须取1.
代码:
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; #define MAX 500005 #define MAXN 6005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); //const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ LL sum[MAX]; int vis[MAX]; int main(){ int n,m; cin>>n>>m; sum[0]=0; for(int i=1;i<=n;i++){ LL a; scanf("%lld",&a); sum[i]=sum[i-1]^a; } LL ans=0; mem(vis,0); for(int i=62;i>=0;i--){ int num=0; for(int j=1;j<=n;j++){ if(((sum[j]>>i)&1)==0&&!vis[j]){ num++; } } if(num>=m&&((sum >>i)&1)==0&&!vis ){ for(int j=1;j<=n;j++){ if((sum[j]>>i)&1) vis[j]=1; } } else ans+=(1LL<<i); } cout<<ans<<endl; return 0; }
相关文章推荐
- SNMP4J 源码包中的使用说明
- hdu 5690 All X
- Web/HTTP 调试利器(Fiddler)
- Thinking in java 之 内部类
- Java Arrys的用法
- NSDictionary的使用及常用方法(如实始化、添加元素、删除元素、修改元素值等)
- Fiddler(Web/HTTP调试利器)
- 专题:链表结点的删除
- 工作漏洞总结
- oracle返回多个参数
- zookeeper 管理 项目配置文件
- 字典树...(eg.hdu 1251)
- (版本定制)第12课:Spark Streaming源码解读之Executor容错安全性
- demo_音乐播放器_Service
- NavigationBar
- centos删除自带的openjdk并安装sun公司的jdk
- Xcode真机调试中的 "The Developer Disk Image could not be mounted." 问题
- 开始学习语音识别技术
- HTML5引入的新数组TypedArray介绍
- 《Head first in Java学习总结与收获》