博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【CodeForces】925 C.Big Secret 异或
阅读量:6633 次
发布时间:2019-06-25

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

【题目】

【题意】给定数组b,求重排列b数组使其前缀异或和数组a单调递增。\(n \leq 10^5,1 \leq b_i \leq 2^{60}\)
【算法】异或
为了拆位分析,先考虑一个简单的问题:已知一个合法b数组和一个数字"1",求数字”1“是否能插入?
容易发现,”1“插入的位置必须满足前面的数字中有偶数个奇数(可以是0个),因为这样前缀和才能比上一位多1,满足要求。

进一步的,已知一个有y个奇数的合法b数组和x个数字”1“,求数字”1“能否全部插入?

利用上面的结论,容易发现当x<=y+1时,只需要在最前面放一个”1“,然后每隔一个奇数放一个”1“就能满足要求(”1“本身也是奇数)。
而当x>y+1时,无解。

上面这个结论可以扩展,对于第k位,已知有y个第k位为0的数字的合法b数组,和x个第k位为1的在\([1,2^{k+1}-1]\)范围内的数字,求数字能否全部插入?

为什么这样扩展是正确的?一个数字能否插入其实只取决于它的最高的1。因为如果最高位异或变成0,无论低位如何都不合法。如果最高为异或变成1,无论低位如何都合法。

现在考虑做法,如何在插入时保证不跳过每次前缀和为偶数的情况?预处理v[i]表示最高的”1“在第i位的数字列表,从前往后依次确定答案,从低位到高位枚举合法的位数并且数字列表不空就插入,累加前缀和。从低到高枚举就能保证插入的数字的低位一定都是不能插入的,免得低位的”1“使得跳过了前缀和为偶数的情况。

复杂度\(O(60*n)\)

本题的关键在于从将数字插入已有的合法数列的角度考虑。

#include
#include
#define ll long longusing namespace std;vector
v[70];int n;ll ans[100010],cur=0;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ ll u;scanf("%lld",&u); for(int j=60;j>=0;j--)if((u>>j)&1){v[j].push_back(u);break;} } for(int i=1;i<=n;i++){ bool ok=0; for(int j=0;j<=60;j++)if(!(cur&(1ll<

转载于:https://www.cnblogs.com/onioncyc/p/9058173.html

你可能感兴趣的文章
Oracle数据库培训-PLSQL编程
查看>>
突破虚拟化极限,自由畅翔云端
查看>>
F5和VMware-共同交付软件定义的数据中心
查看>>
Java并发编程的艺术
查看>>
批量分发ssh公钥证书
查看>>
iOS encrypt Md5, Sha1,Base64
查看>>
git 常用命令
查看>>
Android系统启动流程(四)Launcher启动过程与系统启动流程
查看>>
jquery增,删,改一个html标签的class名字
查看>>
缓存技术
查看>>
怎么样将自己开发的Android应用程序编译到系统Image中
查看>>
Android度量单位说明(DIP,DP,PX,SP)
查看>>
Spring MVC和Struts2的比较的优点
查看>>
Redis配置文件redis.conf详解学习笔记八
查看>>
c++ qt 组播总结
查看>>
RobotFramework BuiltIn关键字笔记
查看>>
Spring整合JMS(四)——事务管理
查看>>
自己封装的golang 操作数据库方法
查看>>
Spring IOC启动流程学习(一)
查看>>
python tornado
查看>>