其他分享
首页 > 其他分享> > TMOOC 1969 开锁

TMOOC 1969 开锁

作者:互联网

TMOOC 1969 开锁

题目描述

(时间限制:1000ms 内存限制:51200KB)
小明经过千辛万苦,终于来到了 小韩隆的门前。但是小韩隆早有防备,将自己的门锁换成了密码锁。密码锁上有n个数字和一个输入装置。这n个数字是小韩隆刻在锁上的,看来需要解谜了。小明知道小韩隆十分喜欢异或,于是他猜想,这个装置应该是由两个数异或而成。通过小弟们对邻居的询问,小明知道了这个密码是由如下方法构造出的:从n个数字中任选一段数字I到 r,从其中任选一个数X,将这一段数的最大值与x异或起来得到y。锁的密码就是所有y值中的最大值。小明冥思苦想了几个小时,终于发现:因为l、r、x都是他自己选的,所以得到的y值会有很多个。由于小明受到NOIP的打击,十分厌恶“大力出奇迹”,他不想再一个一个试密码。现在他找到了作为小弟的你,想要你告诉他锁的密码是多少。
但是小明没有算到的是,小小明来到了小韩隆家做客,他改变了密码锁的密码。现在密码是这样构造的:从n个数字中任选一段数字I到 r,从其中任选一个数 X,将这一段数的次大值与 x 异或起来得到y。锁的密码就是所有y值中的最大值。因为你十分讨厌小明,不想让他大力出这个密码,所以你要算出小小明改完之后,这个锁的密码是多少,方便误导小明。

输入样例

5
9 2 1 4 7

输出样例

14

样例解释

第一个样例l=1,r=5,选取的x为9,密码为7^9=14。
第二个样例1=1,r=4,选取的x为9,密码为4^9=13。另一种可行的方案是1=1,r=4,选取的x为9,密码同样为4^9=13。

数据范围

对于40%的数据:n<=5000。
对于100%的数据:1<=n<=50000,1<=a[i]<=10^9,保证a[i]两两不同。

思路

f[i][j][0]为从i~j的最大值、f[i][j][1]为从i~j的次大值。
那么,对于任意i~j,a[i]来说,

  1. 如果a[i]>f[i][j-1][0],那么f[i][j][1]=f[i][j-1][0]f[i][j][0]=a[i](顺位下沿),可以异或的y值为a[i]^a[j...i-1]
  2. 否则如果a[i]>f[i][j-1][1],那么f[i][j][1]=a[i](替换次大),可以异或的y值为a[i]^a[j...i-1]
  3. 否则,那么f[i][j][0]=f[i][j-1][0]f[i][j][1]=f[i][j-1][1],可以异或的y值为f[i][j][1]^a[i](剩下的异或已经处理一遍了)。

但是,这道题N的范围是50000,开f[50000][50000][2]空间肯定会炸。
考虑到第二维度的值只是当前处理的j,可以使用滚动数组降维。
f[i][0]为从i~(当前的j)的最大值、f[i][1]为从i~(当前的j)的次大值。既可解决空间不足的问题。

参考代码

水过了。

#include <cstdio>
#include <cmath>
using namespace std;
int n,a[10001],f[10001][2],ans;
int main() {    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    for(int i=2;i<=n;i++){
        for(int j=1;j<i;j++){
            if(a[i]>f[j][0]){
                f[j][1]=f[j][0];
                f[j][0]=a[i];
                for(int k=j;k<i;k++)ans=ans>(a[k]^a[i])?ans:a[k]^a[i];
            }else if(a[i]>f[j][1]){
                f[j][1]=a[i];
                for(int k=j;k<i;k++)ans=ans>(a[k]^a[i])?ans:a[k]^a[i];
            }else{
                ans=ans>(f[j][1]^a[i])?ans:(f[j][1]^a[i]);
            }
        }
    }
    printf("%d",ans);
}

标签:小明,开锁,1969,int,ans,样例,密码,异或,TMOOC
来源: https://www.cnblogs.com/dmoransky/p/10626454.html