codeforces 811 C. Vladik and Memorable Trip(dp)
题目链接:http://codeforces.com/contest/811/problem/C
题意:给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都要出现在这个区间。
每个区间的价值为该区间不同的数的异或值,现在问你这n个数最大的价值是多少。
题解:一般这种说法的题目都是用dp的,然后显然设dp[i]表示前i个能取得的最大价值,然后再存一下每个数的起始位置和
结束位置然后n*n就可以了,具体看一下代码,挺短的。
#include <iostream> #include <cstdio> #include <cstring> #define inf 0X3f3f3f3f using namespace std; const int M = 5e3 + 10; int a[M] , ft[M] , ed[M] , dp[M] , vis[M]; int main() { int n; scanf("%d" , &n); memset(ft , inf , sizeof(ft));//表示的是数字i开始的位置 memset(ed , 0 , sizeof(ed));//表示的是数字i结束的位置 for(int i = 1 ; i <= n ; i++) { scanf("%d" , &a[i]); ft[a[i]] = min(ft[a[i]] , i); ed[a[i]] = max(ed[a[i]] , i); } memset(dp , 0 , sizeof(dp)); for(int i = 1 ; i <= n ; i++) { dp[i] = dp[i - 1]; memset(vis , 0 , sizeof(vis)); int sum = 0 , st = i; for(int j = i ; j >= 1 ; j--) { if(!vis[a[j]]) { if(ed[a[j]] > i) break; st = min(st , ft[a[j]]); sum ^= a[j]; vis[a[j]] = 1; } if(st >= j) dp[i] = max(dp[i] , dp[j - 1] + sum);//显然当取到的数最小的位置小于等于j时这一串是可以合并的这种递推方法是可以求得所有可能性的 } } printf("%d\n" , dp[n]); return 0; }