CF939 D
CF939 D
- 让你把区间分成 \(k\) 段, 段内用 \(xor\) 连接, 段之间用 \(or\) 连接,问你在结果不大于 \(x\) 的前提下, \(k\) 的最大值
- \(1 \leq n \leq 10^5, 0 \leq x,a_i \leq 2^30\)
- 标签:正向思维,二进制操作,按位贪心(从高到低)
- 参考题解1,参考题解2
- 注释版code
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
using namespace std;
using ll=long long;
const int N=1e5+5;
int t,n,x,ans=-1;
inline void sol(vector<int> a,const int p=30){// now deal with dep p
if(p<0) return ans=max(ans,(int)a.size()),void();
vector<int> pos;//pos: the set of the positione of all element that is 1 in pth bit
//Attention: pos take account for postion, rather than the concrete element
F(i,0,(int)a.size()-1){
if((a[i]>>p)&1) pos.emplace_back(i);
}
//odd
if(pos.size()%2==1 && ((x>>p)&1)==0) return;
//the pth of x is 0 => fail?
if(pos.size()%2==1 && ((x>>p)&1)==1) return sol(a,p-1);
//the pth of x is 1 => continue to solve
//even
bool rmv[(int)a.size()];
vector<int> b,c=a;//copy a to c
memset(rmv,0,sizeof(rmv));
//create the new seq
for(int i=0;i<(int)pos.size();i+=2){//every postion with 1
for(int j=pos[i]+1;j<=pos[i+1];++j){
rmv[j]=1; c[pos[i]]^=c[j];
}
}
F(i,0,(int)a.size()-1){
if(!rmv[i]) b.emplace_back(c[i]);
}
//make decision
if(((x>>p)&1)==0) return sol(b,p-1);//注意是return.两种情况选其一,单次复杂度就是 O(N)
ans=max(ans,(int)b.size());
//如果x上的这一位是1,第一,若按b这种分法,那么已经最优了
return sol(a,p-1);
//第二,那么其实这一位的限制没有任何意义,仍然踩在a的基础上,直接去考虑下一位.
}
//核心:倒着做,简单来说对于每一次操作,奇数个1就直接考虑最终结果,
//偶数个1就按最优策略(相邻两两配对)添加xor,这样能使这一位上的异或和最终一定为0(尽可能小),剩下没确定符号的位置在solve(b,p-1)中继续讨论
//发现了吗,没有讨论or添加的过程,或者换句话说or的添加过程是依靠贪心来约束的.
//b.size()即段数,不一定最优
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>t; while(t--){
cin>>n>>x;
vector<int> a(n);
F(i,0,n-1) cin>>a[i];
ans=-1;
sol(a);
cout<<ans<<'\n';
}
return 0;
}
- 反思:
- 经典的二进制贪心,从低位到高位。核心在以贪心的方式把 \(or\) 运算给回避掉了,这样就这剩下一种运算需要处理。
- 另一方面就是直白的正向思维(感觉有点儿反套路化逆向思维的感觉),就逐渐逐渐加符号上去,而不是先全填成 \(or\) 或者 \(xor\) 再去改。想多了的话反而容易遭。
- 二进制贪心不一定是什么一个前缀相同然后0,1之间讨论大小关系, 但共同点是两种贪心都和势能很像:只关注已有的条件来推测最终的结果,中间具体状态不关心。
随机推荐
- C#/.NET/.NET Core技术前沿周刊 | 第 1 期(2024年8.12-8.18)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用的技术文章.社区动态.优质项目和学习资源等.让你时刻站 ...
- 卷积神经网络CNN实战:MINST手写数字识别——调用模型/模型预测
import torch import torchvision.transforms as transforms from PIL import Image import numpy as np im ...
- PCIe简介
PCIe简介 Peripheral Component Interconnect Express (PCI),高速串行计算机扩展总线标准,PCIe对外围设备的组织方式是树形结构. 拓扑结构 根: 树的 ...
- 【YashanDB知识库】ycm托管数据库时报错OM host ip:127.0.0.1 is not support join to YCM
问题现象 托管数据库时检查报错OM的IP是127.0.0.1,不支持托管到YCM OM 问题的风险及影响 导致数据库无法托管监控 问题影响的版本 问题发生原因 安装数据库时修改了OM的监听ip为127 ...
- vue 实现组件全屏展示及退出
vue 实现组件全屏展示及退出 一.组件 采用 vue-fullscreen 组件 二.实现方式 <fullscreen ref="fullscreen" @change=& ...
- Angular 学习笔记 (Typescript 高级篇)
由于 typescript 越来越复杂. 所以特意开多一个篇幅来记入一些比较难的, 和一些到了一定程度需要知道的基础. 主要参考 https://basarat.gitbook.io/typescri ...
- C++ cout打印输出 (解决输出乱码)
cout打印输出 输出单份内容 // 输出单份内容 cout << "Hello World!" << endl; cout << 10 < ...
- 深入理解Java对象结构
一.Java对象结构 实例化一个Java对象之后,该对象在内存中的结构是怎么样的?Java对象(Object实例)结构包括三部分:对象头.对象体和对齐字节,具体下图所示 1.Java对象的三部分 (1 ...
- 字节跳动的多平台绽放秘诀 | Flutter 开发者故事
字节跳动旗下运营着一系列成功的用户产品.企业应用以及服务,覆盖信息.教育.娱乐等不同领域.随着产品阵容的不断发展,传统的原生双平台开发已经难以满足团队更高效.更灵活.更精美,以及更多样的产品研发需求. ...
- Docker安装(安装Docker-CE)(三)
现版本安装Docker已经非常简单了,有很多种方式,而自17年开始,Docker分为Docker-CE(社区版).Docker-EE(企业版),另外Docker-IO是较早的版本,通常用的都是Dock ...