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 ;
}

【dp】codeforces C. Vladik and Memorable Trip的更多相关文章

  1. CodeForces - 811C Vladik and Memorable Trip(dp)

    C. Vladik and Memorable Trip time limit per test 2 seconds memory limit per test 256 megabytes input ...

  2. Codeforces 811C Vladik and Memorable Trip (区间异或最大值) (线性DP)

    <题目链接> 题目大意: 给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都只能出现在这个区间. 每个区间的价值为该区间不同的数的异或值之和,现在问你这n个数最大的价值是 ...

  3. CodeForces 811C Vladik and Memorable Trip

    $dp$. 记录$dp[i]$表示以位置$i$为结尾的最大值. 枚举最后一段是哪一段,假设为$[j,i]$,那么可以用$max(dp[1]...dp[j-1]) + val[j][i]$去更新$dp[ ...

  4. [CodeForces - 1225E]Rock Is Push 【dp】【前缀和】

    [CodeForces - 1225E]Rock Is Push [dp][前缀和] 标签:题解 codeforces题解 dp 前缀和 题目描述 Time limit 2000 ms Memory ...

  5. 【CF1256】Codeforces Round #598 (Div. 3) 【思维+贪心+DP】

    https://codeforces.com/contest/1256 A:Payment Without Change[思维] 题意:给你a个价值n的物品和b个价值1的物品,问是否存在取物方案使得价 ...

  6. Kattis - honey【DP】

    Kattis - honey[DP] 题意 有一只蜜蜂,在它的蜂房当中,蜂房是正六边形的,然后它要出去,但是它只能走N步,第N步的时候要回到起点,给出N, 求方案总数 思路 用DP 因为N == 14 ...

  7. HDOJ 1423 Greatest Common Increasing Subsequence 【DP】【最长公共上升子序列】

    HDOJ 1423 Greatest Common Increasing Subsequence [DP][最长公共上升子序列] Time Limit: 2000/1000 MS (Java/Othe ...

  8. HDOJ 1501 Zipper 【DP】【DFS+剪枝】

    HDOJ 1501 Zipper [DP][DFS+剪枝] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...

  9. HDOJ 1257 最少拦截系统 【DP】

    HDOJ 1257 最少拦截系统 [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...

随机推荐

  1. Git之删除本地和远程项目

    目录 删除本地项目 删除远程项目 删除本地项目: git rm -rf project  或者 rm -rf project   [删除工作区项目] git add project [将删除的项目添加 ...

  2. iOS 根据屏幕宽度, 高度判断手机设备

    #define iPhone_5 [UIScreen mainScreen].bounds.size.width == 320.0 #define iPhone_6 [UIScreen mainScr ...

  3. Oracle EXPDP and IMPDP

    一.特点 • 可通过 DBMS_DATAPUMP 调用 • 可提供以下工具: – expdp – impdp – 基于 Web 的界面 • 提供四种数据移动方法: – 数据文件复制 – 直接路径 – ...

  4. QT 学习笔记概述

    以下笔记为在看书和实践的过程中的部分记录总结: 0. 窗口布局 1) 支持绝对布局和布局管理器布局; 2) 绝对布局不够灵活.无法自动调整大小,需要手动编写代码调整: 3) 布局管理器管理布局比较灵活 ...

  5. ArrayList Vector LinkedList分析

    1.创建 ArrayList 的底层是一个数组.  ArrayList<String> list1 = new ArrayList<>(); list1.add("a ...

  6. 汇编4OPCODE

    opcode原理 前缀域 切换操作数大小前缀 : 066h 可以将32位的操作数切换成16位的操作数 B8 00010000 | MOV EAX,0x100     66:B8 0001 | MOV ...

  7. Python3基础教程(十六)—— 迭代器、生成器、装饰器

    在这个实验里我们学习迭代器.生成器.装饰器有关知识. 这几个概念是 Python 中不容易理解透彻的概念,务必把所有的实验代码都完整的输入并理解清楚其中每一行的意思. 迭代器 Python 迭代器(I ...

  8. QT+常见控件+tab Widget 和Stacked Widget

    首先:这里介绍以下tab Widget 和Stacked Widget 之间的区别和使用的方法: tab Widget控件可以直接的进行切换,Stacked Widget却不可以直接在界面上进行切换, ...

  9. 暑假集训 || 树DP

    树上DP通常用到dfs https://www.cnblogs.com/mhpp/p/6628548.html POJ 2342 相邻两点不能同时被选 经典题 f[0][u]表示不选u的情况数,此时v ...

  10. HTML 5 <a> 标签

    href 属性 定义和用法 href 属性规定链接的目标地址. 如果未使用 href 属性,则 <a> 标签不是链接,而是链接的占位符. HTML 4.01 与 HTML 5 之间的差异 ...