您的位置:首页 > 其它

Codeforces Round #416 (Div. 2) C. Vladik and Memorable Trip

2017-06-22 17:20 405 查看
http://codeforces.com/contest/811/problem/C

题意:

给出一行序列,现在要选出一些区间来(不必全部选完),但是相同的数必须出现在同一个区间中,也就是说该数要么不选,选了就必须出现在同一个区间,最后累加区间不同的数的异或值。

思路:

先预处理,求出每个数的左位置和右位置。

d【i】表示分析到第 i 位时的最大值。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn=5000+5;

int a[maxn];
int l[maxn], r[maxn];
int d[maxn];
int vis[maxn];

int main()
{
//freopen("in.txt","r",stdin);
int n;
while(~scanf("%d",&n))
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));

for(int i=1;i<=n;i++)
scanf("%d",&a[i]);

for(int i=1;i<=n;i++)
{
if(l[a[i]] == 0)  l[a[i]]=i;
r[a[i]]=i;
}

int k;
d[0]=0;

//计算以i结尾的最大值
for(int i = 1; i <= n; i++)
{
d[i] = d[i-1];
if(r[a[i]] != i)  continue;

int left = l[a[i]], right = i;
int res = 0;
memset(vis, 0, sizeof(vis));
for(k = right; k >= left; k--)
{
if(!vis[a[k]])
{
if(r[a[k]] > right)  break;          //超出区间
if(l[a[k]] < left)  left = l[a[k]];  //如果区间内的数的左端点小于此时的left,那么left就得变成该数的left
res^= a[k];
vis[a[k]]=1;
}
}

if(k == left - 1)
{
d[i]=max(d[i],d[left - 1] + res);
}

}
printf("%d\n",d
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: