题目来源:http://codeforces.com/problemset/problem/811/C
记录区段中各数的出现次数,若与总数想等则该数符合题意。如果区段中所有出现的数的总数均与总数相等,则更新区段的值。
dp时,f[i]表示1~i的所有选中区段的和的最大值,方程f[i]=max(f[i],f[j-1]+s[j][i])(j<i)(s为区段亦或值)。
提供一组数据:
Input
100 4 3 5 5 2 0 4 0 1 5 1 2 5 5 2 0 2 3 0 0 0 5 4 4 3 0 5 5 4 0 4 4 1 2 0 4 3 5 4 3 5 1 1 0 0 4 2 0 5 0 1 5 3 3 4 5 1 2 2 5 0 3 3 1 2 0 1 3 0 4 5 4 4 1 5 3 0 2 3 4 1 5 5 0 5 0 0 3 2 1 4 3 4 1 4 5 3 0 5 3
Output
1
所选区段为整个区段。故结果为0^1^2^3^4^5=1。
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
const int maxn=5001;
int a[maxn];
int l[maxn];
int r[maxn];
int cnt=0;
int p[maxn];
int s[maxn][maxn];
int f[maxn];
int vis[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
cnt=max(cnt,a[i]);
if(!l[a[i]])l[a[i]]=i;
r[a[i]]=i;
p[a[i]]++;
}
for(int i=1;i<=n;i++)
{
int num=0;
int tot=0;
memset(vis,0,sizeof(vis));
for(int j=i;j<=n;j++)
{
if(!vis[a[j]])
{
num=num^a[j];
tot++;
}
vis[a[j]]++;
if(vis[a[j]]==p[a[j]])tot--;
if(!tot)s[i][j]=num;
}
}
for(int i=1;i<=n;i++)
{
f[i]=f[i-1];
for(int j=1;j<=i;j++)f[i]=max(f[i],f[j-1]+s[j][i]);
}
cout<<f[n];
return 0;
}