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 个元素的数组, ...
随机推荐
- jenkins及Maven介绍
一.环境介绍 随着软件开发需求及复杂度的不断提高,团队开发成员之间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题.Jenkins自动化部署可以解决集成.测试.部署等重复性的 ...
- NumPy学习指南(第2版)
第一章 NumPy快速入门 首先,我们将介绍如何在不同的操作系统中安装NumPy和相关软件,并给出使用NumPy的简单示例代码. 然后,我们将简单介绍IPython(一种交互式shell工具). 如前 ...
- 热门云服务超87GB电子邮箱和密码泄露,黑客已验证大部分数据
热门云存储服务Mega被曝发现超87GB电子邮件地址和密码泄露(源数据目前已被删除,但已流传到个别黑客网站),其中包含近7.73亿电子邮件地址和2200万密码. 近日,国外一名安全研究人员Troy H ...
- matlab画图(一)
例1.画出函数图像 >> x=-pi/2:0.01:pi/2; >> y=x+sin(x)+exp(x); >> plot(x,y,'r','Linewidth', ...
- 原生JS设计轮播图
一.效果预览: 由于只能上传2M以下的图片,这里只截取了自动切换的效果: 二.编写语言 HTML.CSS.原生JS 三.编写思路 (一)HTML部分 1..slide意为滑槽,里面存放所有图片: 2. ...
- JAVA编程思想 Ch3.6题
练习6:在练习5的基础上,创建一个新的Dog索引,并对其赋值为Spot对象.测试用==和equals()方法来比较引用结果. public class quan { String name; Stri ...
- 数学--数论--欧拉降幂--P5091 欧拉定理
题目背景 出题人也想写有趣的题面,可惜并没有能力. 题目描述 给你三个正整数,a,m,ba,m,ba,m,b,你需要求:ab mod ma^b \bmod mabmodm 输入格式 一行三个整数,a, ...
- 有向图强连通分量SCC(全网最好理解)
定义: 在有向图中,如果一些顶点中任意两个顶点都能互相到达(间接或直接),那么这些顶点就构成了一个强连通分量,如果一个顶点没有出度,即它不能到达其他任何顶点,那么该顶点自己就是一个强连通分量. 做题的 ...
- HTML(表单标签)
<form> 标签 用于为用户输入创建 HTML 表单 表单能够包含 input 元素,比如:文本字段.复选框.单选框.提交按钮等等 表单用于向服务器传输数据 action 属性:规定当提 ...
- docker批量删除本地镜像和容器
长时间运行docker,每次只用docker kill去停止容器,但是从没删除过本地镜像,导致有上百个镜像在占用内存. 1.批量停止容器 docker container stop $(docker ...