牛客 小a与星际探索
链接:https://ac.nowcoder.com/acm/contest/317/C
来源:牛客网
小a正在玩一款星际探索游戏,小a需要驾驶着飞船从1号星球出发前往n号星球。其中每个星球有一个能量指数p。星球i能到达星球j当且仅当pi>pj。
同时小a的飞船还有一个耐久度t,初始时为1号点的能量指数,若小a前往星球j,那么飞船的耐久度会变为t⊕pj(即t异或pj,关于其定义请自行百度)
小a想知道到达n号星球时耐久度最大为多少
同时小a的飞船还有一个耐久度t,初始时为1号点的能量指数,若小a前往星球j,那么飞船的耐久度会变为t⊕pj(即t异或pj,关于其定义请自行百度)
小a想知道到达n号星球时耐久度最大为多少
注意:对于每个位置来说,从它出发可以到达的位置仅与两者的p有关,与下标无关
输入描述:
第一行一个整数n,表示星球数
接下来一行有n个整数,第i个整数表示pi
输出描述:
一个整数表示到达n号星球时最大的耐久度
若不能到达n号星球或到达时的最大耐久度为0则输出−1
示例1
备注:
1⩽n,∀pi⩽3000
这题很明显线性基,但是一开始做的时候没有看到 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; }
此为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; }