vijos 紫色的手链

来源:互联网 发布:防火女捏脸数据 编辑:程序博客网 时间:2024/04/19 19:38

思路

先考虑简单的几个数的情况,
比如数组[1,2,3],那么我们要比较的就是1^2,2^3的大小关系。
注意到1^3的情况不在考虑范围中,因为对于1到3的这段区间,次大数为2,
所以ans[1,2,3] 其实也就等于 ans[2,3](ans就是指最终的答案), 1已经不需要再考虑了。
这是问题的突破口。

也就是说,假定数组一开始的两个数是 a , b,且 a<b
我们先用 (a^b) 更新 ans 值,然后对于其他的区间,我们发现都不再需要a来更新答案了。

比如区间[1…n] (n>2),
要么存在两个数都大于 b(最大数次大数就是这两个数),
要么只存在一个数大于 b(最大数是这个数,次大数是 b),
要么不存在大于 b 的数,存在比 a 大的数(最大的比 a 大的数是次大数,最大数是 b)
要么其他所有的数都比 a,b 小(最大数次大数是 b,a,已经更新过答案)。
这四种情况中,没有一种是需要再次用 a 来更新答案的。
所以,我们更新了a^b后,就可以把 a 舍弃掉。

扩展一下,不仅仅在开头两个位置,在序列里任意一个位置,若出现了两个数升序的情况(a 在 b 左边,a<b),我们都可以在用a^b更新答案后,把 a 舍弃掉。
也就是说,我们可以维护一个严格降序的单调序列

举个例子,数组是[6,4,2],此前我们依次用6^4,4^2更新答案,
然后再加一个数:
如果这个数是5,那么先用2^5更新答案,然后舍弃2(2已经用不到了),
再用4^5更新答案,4照样也不再需要用到,舍弃4,
最后用6^5更新答案,把5加入序列,变成[6,5].

所以最终算法是,
用 stack 实现,第一个元素入栈,后面加元素时,把栈头小于新元素的数全部压出栈(出栈同时更新答案),再用新元素和栈头更新答案,新元素入栈。

代码

#include<cstdio>#include<stack>using namespace std;stack <int> sta;int Max(int x,int y){    if (x>=y) return x;    return y;}int main(){    int n,x,ans=0;    scanf("%d",&n);    scanf("%d",&x);    sta.push(x);    for(int i=2;i<=n;++i)    {        scanf("%d",&x);        while(!sta.empty()&&sta.top()<=x)        {            ans=Max(ans,x^sta.top());            sta.pop();        }        if(!sta.empty()) ans=Max(ans,x^sta.top());        sta.push(x);    }    printf("%d\n",ans);    return 0;}

强调

栈操作时,凡涉及 pop / top 操作,切记判断栈空。

原创粉丝点击