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之间讨论大小关系, 但共同点是两种贪心都和势能很像:只关注已有的条件来推测最终的结果,中间具体状态不关心。

随机推荐

  1. 2024九省联考 数学 T19

    寒假有朋友打电话吐槽九省联考,看了眼数学卷子感觉非常刺激.刚开学没事干,试着做一下 \(19\). (\(17\) 分) 离散对数在密码学中有重要的应用.设 \(p\) 是素数,集合 \(X=\{1, ...

  2. Linux与windows共享文件的神器:samba

    一.什么是samba? 搭建Samba服务器是为了实现Linux共享目录之后,在Windows可以直接访问该共享目录. 现在介绍如何在ubuntu 16.04系统中搭建Samba服务. 二 .samb ...

  3. 前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)

    本章开始补充一些基础的图形绘制,比如绘制:直线.曲线.圆/椭形.矩形.这一章主要分享一下本示例是如何开始绘制一个图形的,并以绘制圆/椭形为实现目标. 请大家动动小手,给我一个免费的 Star 吧~ 大 ...

  4. SQL中解决i+1 & values中插入变量

    基于JDBC环境下使用mysql插入数据的一些小问题 下方代码用于实现 批量向数据库中插入数据 一般为"垃圾"数据 代码例子实现i+1的效果 i=1 i+1=2 for (int ...

  5. Adobe Photoshop cc2022 Mac中文破解版下载安装

    PS2024 for Mac,我这个版本是Mac版25.2,大小4.03G,支持intel/M1/M2/M3芯片,最低系统需求:13.4以上,不限速下载地址还是放在最后. 然后安装总共有三个步骤,尤其 ...

  6. IDEA 2023.2 最新安装使用教程(附激活码,亲测好用)

    申明:本教程 IDEA 补丁.补丁均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除.若条件允许,希望大家购买正版 ! idea激活码使用教程 Step1 第一步下载IDEA软件 ID ...

  7. PlugIR:开源还不用微调,首尔大学提出即插即用的多轮对话图文检索 | ACL 2024

    即插即用的PlugIR通过LLM提问者和用户之间的对话逐步改进文本查询以进行图像检索,然后利用LLM将对话转换为检索模型更易理解的格式(一句话).首先,通过重新构造对话形式上下文消除了在现有视觉对话数 ...

  8. 【YashanDB知识库】kettle从DM8的number类型同步到YashanDB的varchar类型,存入是科学计数法形式的数据

    [标题]kettle从DM8的number类型同步到YashanDB的varchar类型,存入是科学计数法形式的数据 [问题分类]数据导入导出 [关键字]数据同步,number类型,科学计数法 [问题 ...

  9. PDF解析,还能做得更好

    随着大模型文档智能应用逐渐步入正轨,文档解析类产品成为其中重要的一环.文档解析工具能够"唤醒"沉睡在PDF文件中的知识,将其转化为机器能够识别.读取的信息,将可用数据从txt.cs ...

  10. OData – 大杂烩

    前言 本篇记入一些 OData 的小东西. Query string too long OData 使用 GET 请求,然后搭配 query string $filter, $select, $exp ...