【CF-811 C. Vladik and Memorable Trip】DP

C. Vladik and Memorable Trip

题意

火车上有n个人,\(a_i\)表示第\(i\)个人要去的地方,可以画若干个不相交的线段,

线段不一定覆盖所有的人,如果\(x\)在某个线段上,那么所有的\(x\)都要在这个

线段上,一个线段的价值为出现在这个线段上不同数字的异或和,列车的

价值为所有线段的价值和,问列车的最大价值。

PS

这是去年一场个人赛的题目,当时我用线段树写的,

WA 到怀疑人生,其实就是忘记清空了。。。而且代码巨长,今天又做到了。

思路

因为是划分线段,很容易想到DP,\(dp[i]\)表示在前i个人中划线段的最大价值。

我们枚举以\(i\)为结尾的线段更新\(dp[i]\)即可。

注意:要保证以\(i\)为结尾的线段,满足题目中的条件是才可以更新\(dp[i]\),具体

见代码。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;

int arr[N],dp[N],minn[N],maxn[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&arr[i]);
        if(!minn[arr[i]])
            minn[arr[i]]=i;
        maxn[arr[i]]=i;
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=dp[i-1];
        int tmp=0,pos=minn[arr[i]];
        for(int j=i;j;j--)
        {
            pos=min(minn[arr[j]],pos);//更新当前线段中数字出现最早的位置
            //如果当前数字最晚出现的位置大于i,那么以i为结尾的线段不符合条件
            if(maxn[arr[j]]>i) break;
            //因为是不同,所以我们只在数字的最小位置进行异或
            if(minn[arr[j]]==j) tmp^=arr[j];
            //当已经遍历过的所有数字的最小位置==j时,才可以更新
            if(pos==j) dp[i]=max(dp[i],dp[j-1]+tmp);
        }
    }
    printf("%d\n",dp[n]);
    return 0;
}
/*
*/
posted @ 2020-05-27 10:30  Valk3  阅读(117)  评论(0编辑  收藏  举报