1. 程式人生 > >TMOOC 1969 開鎖

TMOOC 1969 開鎖

name cst 由於 就是 自己的 tro 限制 sin 替換

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);
}

TMOOC 1969 開鎖