小a与星际探索(dp)

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

 

示例1

输入

复制

3
457 456 23

输出

复制

478

说明

事例2

输入

复制

4
2 4 4 2

输出

复制

-1

示例3

输入

复制

5
234 233 123 2333 23

输出

复制

253

备注:

1⩽n,∀pi⩽3000

 

这道题就是一道简单dp。也不用背包。不过背包也能做。

很多人的方法是不对的,因为异或的性质,当前最大不一定异或了别人也大。后来样例加强了,但也只是加强了一点点。

我起初用的二维dp,int型的会超内存,改成bool才可以,但是那种方法会超时。

后来仔细想了下,简化成了一维。

很简单,就是dp【i】表示当前可不可以达到。

因为一定是由1走向n的,所以1和n肯定都要走。这就是我开始为什么把dp[beginn^endd]=1初始化的原因。其余的点就是在去重,和小于1,大于n的点中选。

循环一下就好了。

可能有人看了第二个代码会有疑问,为什么第一维可以省略。其实我在合法的cnt个点中选了若干个,他们一定是可以有唯一一种顺序相到达的。而我不用考虑这种顺序,我只是要求最大的值是谁。嗯。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=100000;
int dp[7010];
int a[3010],b[3010];
int cmp(int a,int b){
    return a>b;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d",&b[i]);
        }
         int beginn=b[1];
         int endd=b[n];
         if(beginn<=endd){
            printf("-1\n");
            continue;
         }
        sort(b+1,b+1+n,cmp);
        int cnt=1;
        a[1]=beginn;

        for(int i=2;i<=n;i++){
            if(b[i]!=b[i-1] && b[i]<beginn &&b[i]>endd){
                cnt++;
                a[cnt]=b[i];
            }
        }
        n=cnt;
        memset(dp,0,sizeof(dp));
        dp[beginn^endd]=1;

        int maxx=beginn^endd;
         for(int i = 2;i <= cnt;i++){
            for(int j = 0;j < 7000;j++){
                dp[j^a[i]] |= dp[j];
                if(dp[j^a[i]]==1)
                    maxx=max(maxx,j^a[i]);
                if(dp[j]==1){
                    maxx=max(maxx,j);
                }

            }
        }
        if((maxx==0)||(maxx==-1)){
            printf("-1\n");
        }
        else
            printf("%d\n",maxx);
    }
    return 0;
}

 

最开始的二维代码(超时)

我的第一个就是在第二个的基础上做的优化。(天天做水题的我。。)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=100000;
bool dp[3010][4100];
int a[3010],b[3010];
int cmp(int a,int b){
    return a>b;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d",&b[i]);
        }
         a[1]=b[1];
        sort(b+1,b+1+n,cmp);
        int cnt=1;
        for(int i=2;i<=n;i++){
            if(b[i]!=b[i-1] && b[i]<a[1]){
                cnt++;
                a[cnt]=b[i];
            }
        }
        n=cnt;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            dp[i][a[1]]=1;
        }
 
        int maxx=-1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                for(int k=0;k<=4095;k++){
                    if(dp[j][k]==1){///到了i,当前异或值为k有没有
                        dp[i][k^a[i]]=1;
                      ///  cout<<"k:"<<k<<"  a[i]:"<<a[i]<<"  "<<(k^a[i])<<endl;
                        if(i==n)
                        maxx=max(maxx,(k^a[i]));
                    }
                }
            }
        }
        if((maxx==0)||(maxx==-1)){
            printf("-1\n");
        }
        else
            printf("%d\n",maxx);
    }
    return 0;
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值