http://codeforces.com/contest/811/problem/C

【题意】

给定一个自然数序列,在这个序列中找出几个不相交段,使得每个段的异或值之和相加最大。

段的异或值这样定义:段中每个不同数字(不重复)相异或。

段有这样的要求:段中任意一个数字不会在段外出现。

【思路】

首先预处理每个数字第一次出现和最后一次出现的位置,这样对于一个区间[l,r]就很容易判断是否为满足题意的段。

然后区间DP,dp[i]表示子序列[1,i]的最大值。

状态转移:对于dp[i],最小值为dp[i-1],即a[i]在任意段外;如果a[i]的最后一次出现位置大于i,那么没有更新的余地;否则,可能找到这样的l,S.T.dp[i]=max(dp[i],dp[l-1]+sum[l,i])。

如何找到这样的l?

首先可以肯定的是l最小为first[a[i]],然后遍历[first[a[i]],last[a[i]]]中的每个数,不断更新l=min(l,first[a[k]])。

那么为什么dp[i]不可能是dp[j]+sum[j-1,i](j<l)?

因为这样的j一定不满足[j,i]是一个满足题意的段.

如果last[a[j]]<last[a[i]],那么刚刚在遍历[first[a[i]],last[a[i]]]的时候应该已经找到j,即j>=l,矛盾

如果last[a[j]]>last[a[i]],这样的段也不满足题意。

【TLE】

 #include <iostream>
#include <stdio.h>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <ctime>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
const int maxn=;
int a[maxn];
int fir[maxn];
int last[maxn];
int dp[maxn]; int check(int l,int r)
{
int vis[maxn];
memset(vis,,sizeof(vis));
for(int i=l;i<=r;i++)
{
if(last[a[i]]>r||fir[a[i]]<l)
{
return -;
}
}
int x=;
for(int i=l;i<=r;i++)
{
if(!vis[a[i]])
{
x^=a[i];
vis[a[i]]=;
}
}
return x;
}
int main()
{
while(~scanf("%d",&n))
{
memset(dp,,sizeof(dp));
memset(fir,,sizeof(fir));
memset(last,,sizeof(last));
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(!fir[a[i]])
{
fir[a[i]]=i;
}
last[a[i]]=i;
}
for(int i=;i<=n;i++)
{
// cout<<fir[a[i]]<<" "<<last[a[i]]<<endl;
}
for(int i=;i<=n;i++)
{
dp[i]=dp[i-];
for(int k=;k<=i;k++)
{
int num=check(k,i);
if(num>)
{
dp[i]=max(dp[i],dp[k-]+num);
}
}
// printf("dp[%d]=%d\n",i,dp[i]);
}
cout<<dp[n]<<endl; }
return ;
}

一开始没想到怎样找l的方法,直接枚举,时间复杂度O(n^3)(1^2+2^2+.....+n^2=n(n+1)(2n+1)/6)

【Accepted】

 #include <iostream>
#include <stdio.h>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <ctime>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
const int maxn=;
int a[maxn];
int fir[maxn];
int last[maxn];
int dp[maxn]; int sum(int l,int r)
{
int vis[maxn];
memset(vis,,sizeof(vis));
int x=;
for(int i=l;i<=r;i++)
{
if(!vis[a[i]])
{
x^=a[i];
vis[a[i]]=;
}
}
return x;
}
int main()
{
while(~scanf("%d",&n))
{
memset(dp,,sizeof(dp));
memset(fir,,sizeof(fir));
memset(last,,sizeof(last));
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(!fir[a[i]])
{
fir[a[i]]=i;
}
last[a[i]]=i;
}
for(int i=;i<=n;i++)
{
dp[i]=dp[i-];
if(last[a[i]]==i)
{
int l=fir[a[i]];
bool flag=true;
for(int k=l+;k<last[a[i]];k++)
{
if(last[a[k]]>i)
{
flag=false;
break;
}
l=min(l,fir[a[k]]);
}
if(flag)
{
dp[i]=max(dp[i],dp[l-]+sum(l,i));
}
}
}
cout<<dp[n]<<endl;
}
return ;
}

最新文章

  1. .net 控件
  2. USACO Sorting a Three-Valued Sequence
  3. Vue学习笔记1
  4. cocos2d-x之初试内存管理机制
  5. HDOJ 2089 不要62
  6. javascript DOM对象
  7. [NYIST737]石子合并(一)(区间dp)
  8. easyUI中treegrid组件构造树形表格(简单数据类型)+ssm后台
  9. HTML5增加的几个新的标签
  10. iOS性能优化技术
  11. String,StringBuffer,StringBuilder的区别
  12. dedecms织梦的不同栏目调用不同banner图的方法
  13. Spring Security 内置过滤器表
  14. 2019/3/4 java集合学习(二)
  15. Golang 对MongoDB的操作简单封装
  16. [Hive_4] Hive 插入数据
  17. 一次完整的从webshell到域控的探索之路
  18. 关于Redis的配置
  19. 20155226《网络攻防》 Exp3 免杀原理与实践
  20. Win10+vs2012+cuda8.0的安装与配置

热门文章

  1. checkbox:click事件触发文本框显示隐藏
  2. C++模板类头文件和实现文件分离
  3. CCF|学生排队|Java
  4. flutter基础
  5. Hive工具类
  6. 最新精品 强势来袭 XP,32/64位Win7,32/64位Win8,32/64位Win10系统【国庆版版】
  7. QT 学习笔记概述
  8. python之路——内置函数和匿名函数
  9. 运行外部exe
  10. element-ui date-picker 设置结束时间大于等于开始时间且开始时间小于等于结束时间