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 个元素的数组, ...
随机推荐
- FPM制作Nginx的RPM软件包
FPM制作Nginx的rpm软件包 FPM相关参数-s:指定源类型-t:指定目标类型,即想要制作为什么包-n:指定包的名字-v:指定包的版本号-C:指定打包的相对路径-d:指定依赖于哪些包-f:第二次 ...
- 徐州赛区网络预赛 D Easy Math
比赛快结束的适合看了一下D题,发现跟前几天刚刚做过的HDU 5728 PowMod几乎一模一样,当时特兴奋,结果一直到比赛结束都一直WA.回来仔细一琢磨才发现,PowMod这道题保证了n不含平方因子, ...
- 【ElasticSearch学习】之一图读懂文档索引全过程
ES索引过程详解: 1.客户端发送索引请求. 客户端向ES节点发送索引请求,以RestClient客户端发起请求为例: ES提供了Java High Level REST Client,用户可以通过R ...
- Pattern Matching
字符串模式匹配,即子串的定位操作.就是判断主串S中是否存在给定的子串,如果存在,那么返回子串在S中的位置,否则返回0. 实现这种操作有两种算法: 朴素的模式匹配算法 设主串S长度为n,子串T长度为m. ...
- App 抓包代理设置
1.设置 Fiddler 打开 Fiddler,Tools --> Fiddler Options --> HTPS (配置完后记得要重启 Fiddler) 选中 "D ...
- ubuntu 使用 vsftpd 基于系统用户配置相互隔离的 ftp (ftps) 服务
我们在日常使用 UbuntuServer 服务器时,经常会直接使用基于 ssh 的 sftp 连接服务器直接进行文件上传和下载,不过这个方式其实有一定的安全隐患,当一个团队有多个人员,需要连接服务器 ...
- Codeforces Round #637 (Div. 2) 题解
A. Nastya and Rice 网址:https://codeforces.com/contest/1341/problem/A Nastya just made a huge mistake ...
- Dubbo(六):zookeeper注册中心的应用
Dubbo中有一个非常本质和重要的功能,那就是服务的自动注册与发现,而这个功能是通过注册中心来实现的.而dubbo中考虑了外部许多的注册组件的实现,zk,redis,etcd,consul,eurek ...
- 使用python实现模拟掷骰子数据分析
Data:2020/4/8 主题:模拟实现掷骰子数据分析 编译环境:pycharm 库:pygal 说明: code 1:创建一个掷骰子类对象,类方法获得掷骰子随机数1-6,默认6个面,模拟20次将结 ...
- mui日期设置与时钟样式时间设置
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...