P4098 [HEOI2013]ALO
最近这个家伙去哪了,为啥一直不更博客了呢?原来他被老师逼迫去补了一周的文化课,以至于不会把班里的平均分拉掉太多。好了,我们来看下面这道题目:
P4098 [HEOI2013]ALO
题目描述
Welcome to ALO ( Arithmetic and Logistic Online)。这是一个 VR MMORPG, 如名字所见,到处充满了数学的谜题
现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, …, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值 为 k,则生成的宝石的能量密度为 max{k xor ap | ap ≠ k , i ≤ p ≤ j}
现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最 大
输入输出格式
输入格式:
第一行,一个整数 n,表示宝石个数
第二行,n 个整数,分别表示 a1 至 an,表示每颗宝石的能量密度,保证对于 i ≠ j 有 ai ≠ aj
输出格式:
输出一行一个整数,表示最大能生成的宝石能量密度
输入输出样例
5
9 2 1 4 7
14
首先关于异或和什么的问题,一看就要用到trie,然而又是有区间限制,所以一定要访问某个历史版本,自然就是可持久化trie了。那么最重要的问题来了,我们如何找到以每个数为次大值最大的区间呢?首先我们可以想到,如果一个区间里一个数为次大值,那么最大值要么在这个数的左边,要么在这个数的右边,所以我么就可以维护每个数左边比它大的两个数l1、l2,和右边比这个数大的两个数r1、r2这样区间就是(l1,r2)和(l2,r1)这两个区间,那么如何求解每个数的l1,l2,r1,r2呢,这里有两种方法。
第一种,我们可以用ST表预处理然后左右进行二分查找,但是考虑到有些数可能没有l1,l2,r1,r2,这样就需要进行特判,细节巨多无比所以不建议用这种做法。
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#define maxn 50005
using namespace std; inline int read()
{
int x=,res=;
char c=getchar();
while(c<''||c>'')
{
if(c=='-')
x=-;
c=getchar();
}
while(c>=''&&c<='')
{
res=res*+(c-'');
c=getchar();
}
return res*x;
} int n,tot,ans;
int a[maxn],f[maxn][],lg[maxn],tree[maxn*][],last[maxn*];
int root[maxn];
int l,r; int zuo(int l,int r,int rr)
{
if(l>r) return ;
int s=lg[r-l+];
int u=max(f[l][s],f[r-(<<s)+][s]);
if(u<=a[rr])
{
return ;
}
else
{
while(l<=r)
{
int mid=(l+r)>>;
s=lg[r-mid+];
if(max(f[mid][s],f[r-(<<s)+][s])>a[rr])
{
l=mid+;
}
else
{
r=mid-;
}
}
return r;
}
} int you(int l,int r,int ll)
{
if(l>r) return ;
int s=lg[r-l+];
int u=max(f[l][s],f[r-(<<s)+][s]);
if(u<=a[ll])
{
return ;
}
else
{
while(l<=r)
{
int mid=(l+r)>>;
s=lg[mid-l+];
if(max(f[l][s],f[mid-(<<s)+][s])>a[ll])
{
r=mid-;
}
else
{
l=mid+;
}
}
return l;
}
} int ask(int l,int val,int k,int now)
{
if(k<) return val^a[last[now]];
int c=(val>>k)&;
if(last[tree[now][c^]]>=l)
{
return ask(l,val,k-,tree[now][c^]);
}
else
{
return ask(l,val,k-,tree[now][c]);
}
} void trie(int i,int k,int l,int r)
{
if(k<)
{
last[r]=i;
return;
}
int c=(a[i]>>k)&;
if(l) tree[r][c^]=tree[l][c^];
tree[r][c]=++tot;
trie(i,k-,tree[l][c],tree[r][c]);
last[r]=max(last[tree[r][]],last[tree[r][]]);
} int main()
{
n=read();lg[]=-;
last[]=-;
for(int i=;i<=n;i++)
{
a[i]=read();
root[i]=++tot;
trie(i,,root[i-],root[i]);
}
for(int i=;i<=n;i++)
{
f[i][]=a[i];
lg[i]=lg[i>>]+;
}
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=n;i++)
{
f[i][j]=max(f[i][j-],f[i+(<<(j-))][j-]);
}
for(int i=;i<=n;i++)
{
int l1=-,l2=-,r1=-,r2=-,pd=;
l1=zuo(,i,i);
if(l1!=)
{
l2=zuo(,l1-,i);
if(l2==)
l2=;
}
else
{
l2=;
}
r1=you(i,n,i);
if(r1!=)
{
r2=you(r1+,n,i);
if(r2==)
r2=n+;
}
else
{
pd=;r1=r2=n+;
}
if(l1)
{
ans=max(ans,ask(l2+,a[i],,root[r1-]));
}
if(pd==)
{
ans=max(ans,ask(l1+,a[i],,root[r2-]));
}
}
cout<<ans;
return ;
}
ST表+二分
第二种,我们可以先用双向链表储存每一个数的左右两边的数,然后对序列进行排序,再从最小的元素开始依次查找,每查完一个元素我们就把它从链表里删除,这样链表中存的就一定是每个元素左右两边的第一个比它大的元素那么左边的左边就l2,右边的右边就是r2,这样就实现了查询,另外我们只需特判表头和表尾两个元素就行,实现起来也非常简单。
#include<iostream>
#include<string>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#define maxn 50005
using namespace std; struct edge
{
int a,b;
}g[maxn]; inline int read()
{
int x=,res=;
char c=getchar();
while(c<''||c>'')
{
if(c=='-')
x=-;
c=getchar();
}
while(c>=''&&c<='')
{
res=res*+(c-'');
c=getchar();
}
return res*x;
} int n,tot,ans;
int a[maxn],last[maxn*],tree[maxn*][],root[maxn],lx[maxn],rx[maxn]; void trie(int i,int k,int l,int r)
{
if(k<)
{
last[r]=i;
return;
}
int c=(a[i]>>k)&;
if(l) tree[r][c^]=tree[l][c^];
tree[r][c]=++tot;
trie(i,k-,tree[l][c],tree[r][c]);
last[r]=max(last[tree[r][]],last[tree[r][]]);
} int ask(int now,int val,int k,int l)
{
if(k<) return val^a[last[now]];
int c=(val>>k)&;
if(last[tree[now][c^]]>=l)
{
return ask(tree[now][c^],val,k-,l);
}
else
{
return ask(tree[now][c],val,k-,l);
}
} bool cmp(edge x,edge y)
{
return x.a<y.a;
} int main()
{
n=read();
last[]=-;
for(int i=;i<=n;i++)
{
a[i]=read();
g[i].a=a[i];g[i].b=i;
lx[i]=i-;rx[i]=i+;
root[i]=++tot;
trie(i,,root[i-],root[i]);
}
sort(g+,g++n,cmp);
for(int i=;i<=n;i++)
{
int v=g[i].b;
int l=lx[v],r=rx[v];
lx[r]=l;rx[l]=r;
if(l!=)
ans=max(ans,ask(root[r-],g[i].a,,lx[l]+));
if(r!=n+)
ans=max(ans,ask(root[rx[r]-],g[i].a,,l+));
}
cout<<ans;
return ;
}
链表做法
其实还有一个问题,就是在做01trie树的时候,要注意什么时候应该建一棵全0树而什么时候不需要,还有就是last[0]为什么要清为负数,我想这些看似不起眼的问题还是要弄明白比较好,毕竟细节决定成败。
P4098 [HEOI2013]ALO的更多相关文章
- P4098 [HEOI2013]ALO 可持久化01Trie
$ \color{#0066ff}{ 题目描述 }$ Welcome to ALO ( Arithmetic and Logistic Online).这是一个 VR MMORPG, 如名字所见,到处 ...
- [LUOGU]P4098[HEOI2013]ALO
BZOJ上的权限题,流下了贫穷的泪水... 可持久化trie的题. 一开始zz了,看错了题,以为是要把所有的宝石缩起来,后来仔细一看好像只缩一次...昨天刷了一晚上的语文病句题白做了... 这样的话就 ...
- BZOJ3166: [Heoi2013]Alo
3166: [Heoi2013]Alo Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 394 Solved: 204[Submit][Status] ...
- bzoj 3166 [Heoi2013]Alo 可持久化Trie
3166: [Heoi2013]Alo Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1227 Solved: 569[Submit][Status ...
- BZOJ 3166: [Heoi2013]Alo
3166: [Heoi2013]Alo Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 923 Solved: 437[Submit][Status] ...
- [BZOJ3166][Heoi2013]Alo 可持久化Trie树
3166: [Heoi2013]Alo Time Limit: 20 Sec Memory Limit: 256 MB DescriptionWelcome to ALO ( Arithmetic a ...
- 【BZOJ3166】[Heoi2013]Alo 可持久化Trie树+set
[BZOJ3166][Heoi2013]Alo Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , ...
- Bzoj 3166 [Heoi2013] Alo 题解
3166: [Heoi2013]Alo Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1118 Solved: 518[Submit][Status ...
- 暴力 【p4098】[HEOI2013]ALO
Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个 VR MMORPG, 如名字所见,到处充满了数学的谜题 现在你拥有 ...
随机推荐
- NodeJS脚本启动工具总结
1. 使用npm 2. 使用pm2 安装: npm install pm2 -g 启动: NODE_ENV=test pm2 start newsCrawler.js 停止: pm2 stop new ...
- 使用pycharm进行远程开发部署调试设置 与 远程部署调试是否必须使用远程主机的解释器?
远程开发部署调试目的: 配置pycharm远程部署调试主要用于本地代码与远程服务器上的代码进行同步,使得本地代码经过修改后,可以很容易的同步到远程服务器上.同时设置pycharm的解释器为远程服务器的 ...
- BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块
题目描述 输入 输出 样例输入 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 样例输出 2 2 1 1 3 2 2 1 提示 N=100000,M=1000000 ...
- Codeforces Round #544 (Div. 3) D F1 F2
题目链接:D. Zero Quantity Maximization #include <bits/stdc++.h> using namespace std; #define maxn ...
- 1.6分布式通讯协议-WebService
RPC 包含的要素(webservice) 协议层:tcp/ip 应用层: http协议 SOAP: http+xml 分布式通信框架-webservice分析 什么是webservice webse ...
- .NET Core微服务系列基础文章
今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有了一个感性的认识.虽然只做了两个 ...
- go语言基础知识笔记(二)之数组和切片
数组和切片知识用的也是比较多,的给我们工作带来很大的便利 (一) 数组 定义:在golang中数组的长度是不可变,数组存放要求是同一种数据类型 //golang中数组定义的四种方法1.先声明,后赋值 ...
- [面试]死锁-最简单的死锁demo
死锁 什么是死锁 (百度百科) 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁 ...
- Dynamics CRM 日常使用JS整理(二)
BPF(Business Process Flow)相关的JS 为Stage添加changed或者selected事件: function fnOnLoad() { Xrm.Page.data.pro ...
- 微信小程序版本自动更新弹窗提示
代码如下: onLaunch () { if (wx.canIUse('getUpdateManager')) { const updateManager = wx.getUpdateManager( ...