题目

题目大意

给你一个数列,每个数为[0,65535][0,65535][0,65535]内的整数。

给定一个位运算操作optoptopt,是andandand、ororor、xorxorxor中的一种。

求每个数左边与这个数进行操作的最大值,以及达到最大值的数量。


思考历程

见到这东西,首先想到的当然是Trie了!

显然,把Trie建出来之后,搞定xorxorxor是分分钟的事情。

然而andandand或ororor该怎么搞?

下面用andandand来举例:

从高位往低位做,如果当前位是111就好说,如果是000,那两边都可以走。

首先想到的是先走一边,再走另一边,可是这显然会爆炸……

然后想到的是BFS下去……但是这样依然很慢,因为有可能一直做到最下面才被删掉……

我想到了某天做的一道题目(好像叫做量子纠缠?),开始思考是否可以用并查集的方式来做。

一开始感觉好像可以,用个标记什么的,如果不做就不合并喽~

然后发现打标记不现实,必须要递归下去合并……

但是询问操作有很多个啊……这意味着做完之后还要再恢复到原样,然后再做……

于是时间复杂度就不能保证了:如果数据里有一堆000,那是不是每次都要把每个子树合并一遍?

所以还是不行……

接着我意识到了不能局限于Trie,可能还有别的做法。

然后我就想到了分块!

可以将前888位和后888位拆开,分别搞。

我的做法是将前面888位建Trie。怎么建?我建了282^828个不同的Trie。

这些Trie为忽略一些位建立的(当某个位是000的时候,选什么都没有关系,所以这一位被忽略了)。

然后我在这些Trie的每个叶子节点上都开了一个表,表示后888位是多少时的数量。

就这样,我就打出一个时间复杂度为O(8∗28n)O(8*2^8n)O(8∗28n)的做法,自我感觉良好,好像可以压线过去……

交上去,爆0……后来找到错误,再次交上去,时间超限40……

开了个O3O3O3就有100……


正解

正解的时间复杂度要少个888。这个“常数”决定了40分和100分的差距。

设fi,jf_{i,j}fi,j​表示之前的数的前888位为iii,它的后888位和后888位为jjj的数进行操作的最大值以及对应的数量。

对于每个数xxx,显然可以拆成x=28a+bx=2^8a+bx=28a+b的形式。

询问的时候,枚举iii,用fi,bf_{i,b}fi,b​来更新答案。

修改的时候,枚举jjj,用b opt jb \ opt\ jb opt j来更新fa,jf_{a,j}fa,j​。

程序十分简短,特别好打。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
int n,type;
char str[5];
int XOR(int a,int b){return a^b;}
int AND(int a,int b){return a&b;}
int OR(int a,int b){return a|b;}
struct Answer{
int val,num;
inline void update(int _val){
if (_val>val)
val=_val,num=1;
else if (_val==val)
num++;
}
}f[256][256];
inline void solve(int opt(int,int)){//懒得打太多,于是干脆将参数设为函数……
for (int i=1;i<=n;++i){
int x,a,b;
scanf("%d",&x);
a=x>>8,b=x&255;
if (i!=1){
int mx=-1,num=0;
for (int j=0;j<256;++j)
if (f[j][b].num){
int tmp=opt(j,a)<<8|f[j][b].val;
if (tmp>mx)
mx=tmp,num=f[j][b].num;
else if (tmp==mx)
num+=f[j][b].num;
}
if (type)
printf("%d %d\n",mx,num);
else
printf("%d\n",mx);
}
for (int j=0;j<256;++j)
f[a][j].update(opt(j,b));
}
}
int main(){
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
scanf("%d%s%d",&n,str,&type);
if (*str=='x')
solve(XOR);
else if (*str=='a')
solve(AND);
else
solve(OR);
return 0;
}

也把我的那个方法贴上来,开了O3……

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
int n,type;
char opt[5];
struct Node{
Node *c[2];
} d[14001];
int tor[14001];
int cnt;
Node *root[256];
int rest[14001][256],nr;
inline void insert(int r,int x){
Node *t=root[r];
for (int i=15;i>=8;--i)
if (r>>i-8&1){
if (!t->c[x>>i&1])
t->c[x>>i&1]=&d[++cnt];
t=t->c[x>>i&1];
}
if (!tor[t-d])
tor[t-d]=++nr;
rest[tor[t-d]][x&255]++;
}
int time1,time2;
int main(){
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
scanf("%d%s%d",&n,opt,&type);
for (int i=0;i<256;++i)
root[i]=&d[++cnt];
if (*opt=='x'){
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
if (i!=1){
Node *t=root[255];
int ans=0;
for (int j=15;j>=8;--j)
if (t->c[(x>>j&1)^1]){
t=t->c[(x>>j&1)^1];
ans|=1<<j;
}
else
t=t->c[x>>j&1];
int *rst=rest[tor[t-d]],mx=-1,y=x&255;
for (int j=0;j<256;++j)
if (rst[j] && (mx==-1 || (y^j)>mx))
mx=y^j;
printf("%d %d\n",ans|mx,rst[y^mx]);
}
insert(255,x);
}
return 0;
}
for (int i=1;i<=n;++i){
int x;
scanf("%d",&x);
if (i!=1){
int mode=0;
Node *t;
if (*opt=='a')
t=root[mode=x>>8];
else
t=root[mode=x>>8^255];
int ans=0;
for (int j=15;j>=8;--j)
if (mode>>j-8&1){
if (t->c[1]){
t=t->c[1];
ans|=1<<j;
}
else
t=t->c[0];
}
else
ans|=x&1<<j;
int *rst=rest[tor[t-d]],y=x&255,mx=-1,ans2=0;
if (*opt=='a'){
for (int j=0;j<256;++j)
if (rst[j]){
if (mx==-1 || (y&j)>mx)
mx=y&j,ans2=rst[j];
else if ((y&j)==mx)
ans2+=rst[j];
}
if (type==1)
printf("%d %d\n",ans|mx,ans2);
else
printf("%d\n",ans|mx);
}
else{
for (int j=0;j<256;++j)
if (rst[j]){
if (mx==-1 || (y|j)>mx)
mx=y|j,ans2=rst[j];
else if ((y|j)==mx)
ans2+=rst[j];
}
if (type==1)
printf("%d %d\n",ans|mx,ans2);
else
printf("%d\n",ans|mx);
}
}
for (int j=0;j<256;++j)
insert(j,x);
}
return 0;
}

这码量的差距啊……

总结

对于位运算,我们的思想不能再局限于Trie了……

分块还是挺有用的啊……

[JZOJ4616] 【NOI2016模拟7.12】二进制的世界的更多相关文章

  1. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  2. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  3. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  4. 【NOIP2017提高A组模拟9.12】Arrays and Palindrome

    [NOIP2017提高A组模拟9.12]Arrays and Palindrome[SPJ] 题目 Description Input Output Sample Input 1 6 Sample O ...

  5. suse 12 二进制部署 Kubernetets 1.19.7 - 第13章 - 部署metrics-server插件

    文章目录 1.13.0.创建metrics-server证书和私钥 1.13.1.生成metrics-server证书和私钥 1.13.2.开启kube-apiserver聚合配置 1.13.3.分发 ...

  6. suse 12 二进制部署 Kubernetets 1.19.7 - 番外篇 - 增加node节点

    文章目录 0.前景提要 1.准备node节点环境 1.0.修改配置脚本参数 1.1.配置免密 1.2.添加hosts解析 1.3.修改主机名 1.4.更新PATH变量 1.5.安装依赖包 1.6.关闭 ...

  7. suse 12 二进制部署 Kubernetets 1.19.7 - 第01章 - 创建CA证书和kubectl集群管理命令

    文章目录 1.kubernetes集群部署 1.0.创建CA证书和秘钥 1.0.0.安装cfssl工具 1.0.1.创建根证书 1.0.2.创建证书签名请求文件 1.0.3.生成CA证书和秘钥 1.0 ...

  8. suse 12 二进制部署 Kubernetets 1.19.7 - 第02章 - 部署etcd集群

    文章目录 1.2.部署etcd集群 1.2.0.下载etcd二进制文件 1.2.1.创建etcd证书和私钥 1.2.2.生成etcd证书和私钥 1.2.3.配置etcd为systemctl管理 1.2 ...

  9. suse 12 二进制部署 Kubernetets 1.19.7 - 第03章 - 部署flannel插件

    文章目录 1.3.部署flannel网络 1.3.0.下载flannel二进制文件 1.3.1.创建flannel证书和私钥 1.3.2.生成flannel证书和私钥 1.3.3.将pod网段写入et ...

随机推荐

  1. 自定义可点击的ImageSpan并在TextView中内置“View“

    有的时候可能想在TextView中添加一些图片,比如下图,发短信输入联系人时,要把联系人号码换成一个图片,但这个图片无法用固定的某张图,而是根据内容进行定制的,这更像一个view. 当然,如果你不是v ...

  2. thinkphp助手函数

    tp3 C($name=null, $value=null,$default=null) 获取和设置配置参数 支持批量定义 load_config($file,$parse=CONF_PARSE) 加 ...

  3. sudo dpkg --configure -a无法解决的问题

    系统升级及新立得启动时出现的问题,还不能安装软件 E: dpkg 的操作被中断了, 您必须手动执行 'sudo dpkg --configure -a' 以修复这个问题. E: _cache-> ...

  4. 【学术篇】2.28测试T2 线段 拓扑排序

    题目: 思路: 看到这种找前后的题目... 第一反应就是拓扑排序_(:з」∠)_ 每条线段都有左右两个端点咯, 然后就乱搞吧.. 我们用\(i\)和\(i'\)分别表示第\(i\)条线段的左右端点.. ...

  5. main中的argc,argv

    那么我们运行程序时,传入的参数,就是这个argc的值:从截图中,我们很清楚的可以看出,argc是传入参数的个数,”传入的参数“加上可执行文件的文件名:  

  6. springcloud -zuul(2-执行流程及源码)

    官方图 1.Servlet zuul.servletPath默认配置为/zuul,故请求为/zuul开头的会跳过dispatcherServlet直接进入ZuulServlet,该配置可以自定义配置, ...

  7. 好久不见的博客咯!——没有可持久化的可持久化treap

    每每想要去了解可持久化treap这个好写好调的东东,然后就发现网上只有一个人的——SymenYang的!在此我必须得把他批判一番——写方法不贴代码是什么心态!而且写出来的是有问题的呀!害人不浅! 好吧 ...

  8. NX二次开发-UFUN旋转视图UF_VIEW_rotate_view

    NX11+VS2013 #include <uf.h> #include <uf_view.h> #include <uf_obj.h> #include < ...

  9. 使用Docker在服务器上部署Ubuntu,本地传文件到docker

    使用Docker在服务器上部署Ubuntu,本地传文件到docker 作者:王佳乐 目录 安装Docker 安装Docker 全部安装流程: 登录服务器 ssh username@ip 检查是否已经安 ...

  10. CSS3:CSS3 渐变(Gradients)

    ylbtech-CSS3:CSS3 渐变(Gradients) 1.返回顶部 1. CSS3 渐变(Gradients) CSS3 渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳 ...