cf811C(预处理&dp)

题目链接: http://codeforces.com/problemset/problem/811/C

题意: 给一个有n个人排队上车,去相同地方的人要么坐在同一个车厢,要不就不上车,问最大舒适度和是多少。苏适度是车厢内所有数组成的集合的异或值。

即: 给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都要出现在这个区间。 每个区间的价值为该区间不同的数的异或值,现在问你这n个数最大的价值是多少。

注意: 相交的区间要么全选要么全不选

思路: dp

dp[i] 存储前 i (即 i 为元素 a[i] 所在区间的右边界)个人最大舒适度值, 对于当前 i , 从 i 往前更新一遍.

动态转移方程式为: dp[i] = max(dp[i], dp[j] + ans) , 其中 ans 为合法区间 [j, i] 的舒适度.

需要先预处理一下 a[i] 所在区间来判断选取区间时的合法性.

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4 
 5 const int MAXN = 5e3 + 10;
 6 int s[MAXN], e[MAXN], a[MAXN], dp[MAXN];
 7 
 8 int main(void){
 9     int n;
10     scanf("%d", &n);
11     for(int i = 1; i <= n; i++){
12         scanf("%d", &a[i]);
13         if(!s[a[i]]) s[a[i]] = i;
14         e[a[i]] = i;
15     }
16     for(int i = 1; i <= n; i++){
17         dp[i] = dp[i -1];
18         int vis[MAXN] = {0,};
19         int cnt = s[a[i]], ans = 0;
20         for(int j = i; j > 0; j--){
21             if(!vis[a[j]]){
22                 if(e[a[j]] > i) break;
23                 cnt = min(cnt, s[a[j]]);
24                 ans ^= a[j];
25                 vis[a[j]] = 1;
26             }
27             if(j == cnt) dp[i] = max(dp[i], dp[j - 1] + ans);
28         }
29     }
30     printf("%d
", dp[n]);
31     return 0;
32 }
View Code
原文地址:https://www.cnblogs.com/geloutingyu/p/7123889.html