CodeForces 811C Vladik and Memorable Trip dp

题意:

(一开始题意没读懂 样例都看不懂

给你n个数 让你选出一些区间 让这些区间的表示的值和最大

每个区间表示的值就是区间内每个不重复的数的异或和

我们选出的区间可以不覆盖整个数组 就像第二组样例

(接下来是重点

区间内出现过的数不能在其他区间出现

意思就是如果一个数在区间中出现过 那所有数就都要在区间里

 

思路:

首先我们要记录每个数第一次和最后一次出现的地方

然后dp一下 枚举每个区间

在符合条件的时候更新就好

具体操作看代码

 

 1 #include<bits/stdc++.h>
 2 #define cl(a,b) memset(a,b,sizeof(a))
 3 #define debug(a) cerr<<#a<<"=="<<a<<endl
 4 using namespace std;
 5 typedef long long ll;
 6 typedef pair<int,int> pii;
 7 
 8 const int maxn=5000+10;
 9 
10 int a[maxn],vis[maxn],dp[maxn];
11 
12 int main()
13 {
14     int n;
15     scanf("%d",&n);
16     //初始化loc
17     //first记录数字i第一次出现的位置
18     //second记录数字i最后一次出现的位置
19     vector<pii>loc(maxn,{0,0});
20     for(int i=1;i<=n;i++)
21     {
22         scanf("%d",&a[i]);
23         if(loc[a[i]].first==0)
24         {//记录这个数第一次出现的位置
25             loc[a[i]].first=i;
26         }
27         loc[a[i]].second=i;//记录最后一次出现的位置
28     }
29     for(int i=1;i<=n;i++)
30     {//枚举区间
31         dp[i]=dp[i-1];//继承之前的状态
32         cl(vis,false);
33         int st=i,sum=0;
34         for(int j=i;j>=1;j--)
35         {//枚举区间右端点
36             if(!vis[a[j]])
37             {
38                 if(loc[a[j]].second>i)
39                 {//如果这个数最后一次出现的位置大于i 就不用计算这个点l
40                     break;
41                 }
42                 //更新区间的起点
43                 st=min(st,loc[a[j]].first);
44                 //更新当前区间sum
45                 sum^=a[j];
46                 vis[a[j]]=true;
47             }
48             if(j<=st)
49             {//如果j可以当作区间左端点的话
50                 dp[i]=max(dp[i],dp[j-1]+sum);//更新区间最值
51             }
52         }
53     }
54     printf("%d\n",dp[n]);
55     return 0;
56 }/*
57 
58 9
59 5 1 3 1 5 2 4 2 5
60 
61 */

 

posted @ 2017-07-19 11:30  良将ℓ  阅读(194)  评论(0编辑  收藏  举报