【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;
}
/*
*/