CF834D
题目链接:http://codeforces.com/contest/834/problem/D
题目大意:将一个有n个数的数列分成k段,每段的价值为该段中不同数字的个数,求k段的最大总价值。
解题思路:
思路来自叉姐 + GreenGrape
dp + segment trees.
dp不难想到。前 i 个数分成 j 段的最大价值:dp[i][j] = max( dp[i-1][k] + w(k+1,j), i-1 <= k < j). 但其实这样直接去搞的话分分钟TLE。
所以,我们需要使用线段树。详情请看代码,里面有个人的注释,请指教。
AC代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <queue> using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define root 1 , N , 1
const int maxn=+;
int a[maxn],dp[][maxn],last[maxn];
int pre[maxn];
int tree[maxn<<],lazy[maxn<<]; //*****************************************************
//这一部分其实就是走模板
void pushup(int rt){
tree[rt]=max(tree[rt<<],tree[rt<<|]);
}
void pushdown(int rt){
if(lazy[rt]){
lazy[rt<<]+=lazy[rt];
lazy[rt<<|]+=lazy[rt];
tree[rt<<]+=lazy[rt];
tree[rt<<|]+=lazy[rt];
lazy[rt]=;
}
}
void update(int L,int R,int c,int l,int r,int rt){
if(L<=l&&r<=R){
lazy[rt]+=c;
tree[rt]+=c;
return;
}
pushdown(rt);
int m=(l+r)>>;
if(L<=m) update(L,R,c,lson);
if(m<R) update(L,R,c,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R)
return tree[rt];
pushdown(rt);
int m=(l+r)>>;
int ret=;
if(L<=m) ret=max(ret,query(L,R,lson));
if(m<R) ret=max(ret,query(L,R,rson));
return ret;
}
//******************************************************* int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
pre[i]=last[a[i]];//pre[i]记录a[i]上一次出现的位置
last[a[i]]=i;
}
for(int i=;i<=k;i++){
memset(tree,,sizeof(tree));
memset(lazy,,sizeof(lazy));
for(int j=i-;j<=n;j++)
update(j,j,dp[i-][j],,n,);//把线段树各叶子结点的值初始化为dp[i-1][]的值,在dp[i][]这一维度上的操作其实就是在dp[i-1][]的基础上进行的。前面不能忘了把线段树的数据置0。
for(int j=i;j<=n;j++){
//对于以x为结尾(pre[j] <= x <= j-1)的dp[i-1][x],将a[j]作为第 i 段的结尾可以使得dp[i-1][x]对应的dp[i][j]的值+1。
//故此时线段树维护的就是max(dp[i-1][k] + w(k+1,j), i-1 <= k < j)。w(k+1,j)在这个更新的过程中逐次加和累积。实在是精妙无比。
update(pre[j],j-,,,n,);
dp[i][j]=query(,j,,n,);
}
}
int ans=;
for(int j=k;j<=n;j++){
if(dp[k][j]>ans) ans=dp[k][j];
}
printf("%d\n",ans);
return ;
}
CF834D的更多相关文章
- CF834D The Bakery
题目链接:戳我 题意:将一个长度为n的序列分为k段,使得总价值最大.一段区间的价值表示为区间内不同数字的个数 \(n<=35000,k<=50\) 开始想的转移方程是这个样子的--\(dp ...
- cf834D(dp+线段树区间最值,区间更新)
题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...
随机推荐
- vuex vue-devtools 安装
vue-devtools是一款基于chrome游览器的插件,用于调试vue应用,这可以极大地提高我们的调试效率.接下来我们就介绍一下vue-devtools的安装 chrome商店直接安装 谷歌访问助 ...
- time wait 整理
目录 状态转换图 1.谁会进入time wait状态: 主动发起断开连接的一方调用close()函数发送FIN并进入FIN WAIT 1状态,当收到对面反馈的ack之后会进入FIN WAIT2状态.之 ...
- json序列化字符串后,配置枚举类型显示数值而不是名称
2019独角兽企业重金招聘Python工程师标准>>> 经常有这么一个需求,实体类里面用到枚举常量,但序列化成json字符串时.默认并不是我想要的值,而是名称,如下 类 @Data ...
- 图论--2-SAT--HDU/HDOJ 1814 Peaceful Commission
Peaceful Commission Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- C# 基础知识系列- 14 IO篇 流的使用
0. 前言 继续之前的C# IO流,在前几篇小短片中我们大概看了下C# 的基础IO也对文件.目录和路径的操作有了一定的了解.这一篇开始,给大家演示一下流的各种操作.以文件流为例,一起来看看如何操作吧. ...
- turtle库应用实例3-叠加等边三角形绘制(一笔画)
叠加等边三角形绘制 ...
- 网络流二十四题,题解summary
没有全部写完,有几题以后再补吧. 第一题:最简单的:飞行员配对方案问题 讲讲这个题目为什么可以用网络流? 因为这个题目是要进行两两之间的匹配,这个就可以想到用二分图匹配,二分图匹配又可以用网络流写. ...
- 201771010113-李婷华 实验一 软件工程准备-<软件工程的相关了解>
项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/nwnu2020SE 这个作业要求链接 https://www.cnblogs.com/nwnu- ...
- MySQL基础总结(三)
ORDER BY排序 ORDER BY默认是ASC(升序),降序是DESC LIMIT限制查询结果显示条数 LIMIT显示条数 LIMIT偏移量,显示条数 到目前为止有关查询数据的操作(DQL) 更新 ...
- Spring Cloud 系列之 Config 配置中心(三)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Config 配置中心(一) Spring Cloud 系列之 Config 配置中心(二) 本篇文章讲解 Conf ...