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 */