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

http://codeforces.com/contest/811/problem/C

题意:

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

 

思路:

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

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

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 using namespace std;
12 typedef long long ll;
13 typedef pair<int,int> pll;
14 const int INF = 0x3f3f3f3f;
15 const int maxn=5000+5;
16 
17 int a[maxn];
18 int l[maxn], r[maxn];
19 int d[maxn];
20 int vis[maxn];
21 
22 int main()
23 {
24     //freopen("in.txt","r",stdin);
25     int n;
26     while(~scanf("%d",&n))
27     {
28         memset(l,0,sizeof(l));
29         memset(r,0,sizeof(r));
30 
31         for(int i=1;i<=n;i++)
32             scanf("%d",&a[i]);
33 
34         for(int i=1;i<=n;i++)
35         {
36             if(l[a[i]] == 0)  l[a[i]]=i;
37             r[a[i]]=i;
38         }
39 
40         int k;
41         d[0]=0;
42         
43         //计算以i结尾的最大值
44         for(int i = 1; i <= n; i++)
45         {
46             d[i] = d[i-1];
47             if(r[a[i]] != i)  continue;
48 
49             int left = l[a[i]], right = i;
50             int res = 0;
51             memset(vis, 0, sizeof(vis));
52             for(k = right; k >= left; k--)
53             {
54                 if(!vis[a[k]])
55                 {
56                     if(r[a[k]] > right)  break;          //超出区间
57                     if(l[a[k]] < left)  left = l[a[k]];  //如果区间内的数的左端点小于此时的left,那么left就得变成该数的left
58                     res^= a[k];
59                     vis[a[k]]=1;
60                 }
61             }
62 
63             if(k == left - 1)
64             {
65                 d[i]=max(d[i],d[left - 1] + res);
66             }
67 
68         }
69         printf("%d\n",d[n]);
70     }
71     return 0;
72 }

 

posted @ 2017-06-22 17:20  Kayden_Cheung  阅读(144)  评论(0编辑  收藏  举报
//目录