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, 如名字所见,到处充满了数学的谜题 现在你拥有 ...
随机推荐
- JavaScript继承总结
1.创建对象 1.字面量对象 2.构造函数 3.Object.create //1.字面量 var obj={ name: '字面量', show: function(){ console.log(t ...
- [CF 666E] Forensic Examination
Description 传送门 Solution 对 \(T[1..m]\) 建立广义后缀自动机,离线,找出代表 \(S[pl,pr]\) 的每个节点,线段树合并. Code #include < ...
- BZOJ2406矩阵——有上下界的可行流+二分答案
题目描述 输入 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. 输出 第一行,输出最小的答案: 样例输入 2 2 0 1 2 1 0 1 样例输出 1 ...
- ShoppingCart
数据库设计 表结构 [dbo].[AdminInfo] AdminID, AdminName, AdminPassword, RoleID [dbo].[BK_Car] ID, CarID, ISBN ...
- VMware虚拟机里Centos7的IP地址查看方法
电脑的虚拟机里面安装了一个Cetos 7 ,想用Xshell链接进行操作,发现没有IP显示,需要IP地址,我才能进行连接,用命令ip addr查看下: 发现ens33 没有inet 这个属性,那么就没 ...
- did not finish being created even after we waited 189 seconds or 61 attempts. And its status is downloading
did not finish being created even after we waited 189 seconds or 61 attempts. And its status is down ...
- 公共DNS推荐及dns测速
DNS在平时上网中扮演重要角色,如果不注意DNS的话,可能会导致网速慢.弹窗广告.网址打不开.打开不是自己想要的网站.劫持等一系列问题.针对DNS的问题,今天我们就来总结一下,看看哪个DNS服务器最好 ...
- 2018-2019-2 网络对抗技术 20165232 Exp4 恶意代码分析
2018-2019-2 网络对抗技术 20165232 Exp4 恶意代码分析 1.实践目标 监控你自己系统的运行状态,看有没有可疑的程序在运行. 分析一个恶意软件,就分析Exp2或Exp3中生成后门 ...
- freetype之PC机体验
目录 freetype之PC机体验 引入 中文教程 官方教程 代码结构 字体概念 PC上安装 官方例子 宽字符保存显示中文 坐标框架体系 字符坐标信息获取 title: freetype之PC机体验 ...
- python3 两层dict字典转置
python3; 两层字典 dict =(type, dict2) dict2 = (k_value, index) dictss = { 10: {3: 1, 4: 2, 5: 3, 6: 4, 7 ...