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 ",d[n]); 70 } 71 return 0; 72 }