牛客 小a与星际探索

链接:https://ac.nowcoder.com/acm/contest/317/C
来源:牛客网

小a正在玩一款星际探索游戏,小a需要驾驶着飞船从1号星球出发前往n号星球。其中每个星球有一个能量指数p。星球i能到达星球j当且仅当pi>pj
同时小a的飞船还有一个耐久度t,初始时为1号点的能量指数,若小a前往星球j,那么飞船的耐久度会变为tpj(即t异或pj,关于其定义请自行百度)
小a想知道到达n号星球时耐久度最大为多少
注意:对于每个位置来说,从它出发可以到达的位置仅与两者的p有关,与下标无关

输入描述:

第一行一个整数n,表示星球数
接下来一行有n个整数,第i个整数表示pi

输出描述:

一个整数表示到达n号星球时最大的耐久度
若不能到达n号星球或到达时的最大耐久度为0则输出1
示例1

输入

复制
3
457 456 23

输出

复制
478

说明

小a有两种方法到达33号星球
第一种:1231→2→3,最终耐久度为45745623=22457⊕456⊕23=22
第二种:131→3,最终耐久度为45723=478457⊕23=478
示例2

输入

复制
4
2 4 4 2

输出

复制
-1
示例3

输入

复制
5
234 233 123 2333 23

输出

复制
253

备注:

1n,pi3000

这题很明显线性基,但是一开始做的时候没有看到 pi 必须大于 pj 这条限制条件 就直接打了,打完发现样例不过,自己也看不懂样例。
重新读了一遍题才发现那个条件,果然电子竞技不需要视力。
只需要把P0作为最大值 Pn-1作为最小值,处理出来新的数组,然后再线性基最大值就行了。


也可以用暴力dp 。
处理出来新的数组,并排序。将本题的移动方式更改为:
从第一个点走到最后一个点,可以自由选择是否在当前点异或(第一个点和最后一个点除外)
dp[i][j] 表示 走到第i个点 并 进行完是否在i处异或的抉择之后,值能否为 j

此代码为线性基的代码。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int arr[3005];
int stu[3005];
int p[15];
int main(){
    int n;
    int cnt=0;
    int ans;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    if(arr[0]<=arr[n-1]){
        puts("-1");
        return 0;
    }
    ans = arr[0]^arr[n-1];
    for(int i=1;i<n-1;i++){
        if(arr[n-1] < arr[i] && arr[i] < arr[0])
            stu[cnt++] = arr[i];
    }
    memset(p,0,sizeof(p));
    for(int i=0;i<cnt;i++){
        for(int j=11;j>=0;j--){
            if(stu[i]>>j&1){
                if(p[j]){
                    stu[i] ^= p[j];
                }else {
                    p[j] = stu[i];
                    break;
                }
            }
        }
    }
    for(int i=0;i<12;i++){
        for(int j=i+1;j<12;j++){
            if(p[j]>>i&1)p[j]^=p[i];
        }
    }
    for(int i=0;i<12;i++){
        if(ans < (ans ^ p[i]))
            ans ^= p[i];
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 此为dp代码。

 

#include   <cstdio>
#include  <cstring>
#include<algorithm>
using namespace std;

const int maxn = (1<<12);
int arr[3005];
int stu[3005];
bool dp[3005][maxn];
bool cmp(int a,int b){
    return a > b;
}
int main(){
    int n;
    int cnt=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&arr[i]);
    if(arr[0]<=arr[n-1]){
        puts("-1");
        return 0;
    }
    stu[cnt++] = arr[0];
    stu[cnt++] = arr[n-1];
    for(int i=1;i<n-1;i++){//处理出新数组
        if(arr[n-1] < arr[i] && arr[i] < arr[0])
            stu[cnt++] = arr[i];
    }

    sort(stu,stu+cnt,cmp);
    dp[0][stu[0]]=1;
    for(int i=1;i<cnt;i++){
        if(i==cnt-1){//最后一个点
            for(int j=maxn-1;j;j--){
                // 从大到小 遍历所有可能的 j 值
                dp[i][j] |= dp[i-1][j ^ stu[i]];
                if(dp[i][j]){printf("%d\n",j);return 0;}
            }
        }else if(stu[i]==stu[i-1]){
            //因为和前一个点的值一样,所以dp的结果也一样
            memcpy(dp[i],dp[i-1],sizeof(dp[i]));
        }else{
            for(int j=0;j<maxn;j++){
                // 在i点的 j 值可以由i-1处用(j^stu[i])这个值来异或stu[i]得到
                // 也可以由 i-1处的j值不在i处异或stu[i]得到
                dp[i][j] |= dp[i-1][j^stu[i]] | dp[i-1][j];
            }
        }
    }
    puts("-1");
    return 0;
}
View Code

 

posted @ 2019-01-22 18:25  kongbb  阅读(200)  评论(0编辑  收藏  举报