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, 如名字所见,到处充满了数学的谜题 现在你拥有 ...
随机推荐
- sqlserver2008R2 评估期已过
早上打开win程序-卡死不动了,查看三层数据库连接-连接不上数据库 打开数据库-提示 评估期已过 解决方法: 进入sqlserver的安装中心-点击 维护-版本升级 输入密钥:企业版:R88PF-GM ...
- IIC时序操作24C02芯片
1.心血来潮看自己能不能参考时序图重新写一个IIC驱动,加强一下时序图的理解.记录下来,以后遇到此类的IIC时序的芯片可以直接操作. 先说说自己参照手册来写AT24c02的IIC低层驱动,从写完到最后 ...
- shell-计算虚拟机创建时间
因为要验证虚拟机创建时间,所以写了下面一个脚本 #!/bin/bash ################################################################ ...
- Python中布尔值是False的所有值
在python中以下都是False:为0的,空集合,空字符串,空值None >>> bool(0) False >>> bool(-0) False >> ...
- [CQOI2016]伪光滑数
题目描述 若一个大于1的整数M的质因数分解有k项,其最大的质因子为Ak,并且满足Ak^K<=N,Ak<128,我们就称整数M为N-伪 光滑数.现在给出N,求所有整数中,第K大的N-伪光滑数 ...
- jmeter笔记(9)--JDBC Request的使用
JDBC Request可以向数据库发送一个JDBC(Java Data Base Connectivity)请求(sql语句),获取返回的数据库数据进行操作.它需要和JDBC Connection ...
- 构建一个maven聚合类型的横向可扩展项目
那个时候初入java这个大家庭,学习的方向很乱.毕业后,在公司磨练了一年,总想着是该交一份答卷了,可能成绩不会很好,但求及格!那么考试题目呢,我计划搭建一个横向可扩展的项目,可以在平台自扩展各种子项目 ...
- Day062--django--模板,母版和继承
1.MVC和MTV MVC C Controller : 逻辑的控制 M Model : 存取数据 V View : 信息的展示 MTV M : model ORM操作 T: Template 模板 ...
- (模拟 打好基础)nyoj1363-计划日
1363-计划日 内存限制:256MB 时间限制:3000ms 特判: No通过数:21 提交数:79 难度:1 题目描述: 为什么花那么多时间.精力还是学不好学不通,如何把握各科目的重难点,期中和期 ...
- JS基础-第5天
复习函数 函数 作用:封装一段代码,封装的功能可以被反复调用执行. 定义函数 // 第一种 - 函数声明 function 函数名(){ } // 第二种 - 函数表达式 var 函数名 = func ...