http://codeforces.com/problemset/problem/811/C
题意是一群人在坐火车。先告诉你有n个人,然后告诉你n个目的地(用数字表示的)。目的地一样的所有人要么都在一辆列车上,要么就都在原地不要动。在同一辆列车上的舒适度,用^计算。
一开始的思路:
虽起点和终点进行预处理并对这个区间求^值。然后转换成一个背包问题,当时还在网上找到一个叫带权区间调度问题。其实就是背包问题的一个变形。感觉我们想的也挺对的。结果我比较傻。。我预处理就写了五六十行。比赛就结束了,后来看了别人的代码。也没有往下写的欲望了。不过听说直接这样写就TLE了。
正确的思路:
其实也是个变形的背包,扫一遍每个目的地,对于当前的状态有两个转移过来的可能,一个是这个人就原地不动了,另一个状态就是找出这个目的地往前推最短的一个合法区间。(合法区间就是这个区间中要么就不要某个目的地,要么就包括了所有要去这个目的地的人)。因为加法肯定要比异或要好吧。所以只找出最短的就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=5005;
int sum[maxn];
int num[maxn];
int a[maxn];
int dp[maxn];
int main(){
int n,xors,p,q;
cin>>n;
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++){
cin>>a[i];
sum[a[i]]++;//sum记录每个目的地的总人数。
}
for(int i=1;i<=n;i++){
dp[i]=dp[i-1];
memset(num,0,sizeof(num));
xors=p=q=0;//p是记录有几个目的地的人已经进入区间。q记录有几个进入区间的目的地的所有人已经找完了
for(int j=i;j>=1;j--){
if(num[a[j]]==0){
xors^=a[j];
p++;
}
num[a[j]]++;
if(num[a[j]]==sum[a[j]]){
q++;
}
if(p==q){//找到了最短的合法区间
dp[i]=max(dp[i-1],dp[j-1]+xors);
break;
}
}
}
printf("%d\n",dp[n]);
return 0;
}
/*
9
5 1 3 1 5 2 4 2 5
0 2 3
3 3 2
0 6 4
4 7 6
6 8 1
6
*/