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 个元素的数组, ...
随机推荐
- pip安装openvc-python国内镜像源
采用清华大学的镜像源. pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghu ...
- Pytorch中自定义神经网络卷积核权重
1. 自定义神经网络卷积核权重 神经网络被深度学习者深深喜爱,究其原因之一是神经网络的便利性,使用者只需要根据自己的需求像搭积木一样搭建神经网络框架即可,搭建过程中我们只需要考虑卷积核的尺寸,输入输出 ...
- vue与众不同的学习方式,让她年薪200多万
学习vue正确思路,是先学vue-cli,再学vue.js单文件引用的用法,这样会在极短时间内撤底撑握vue,如果先学vue.js单文件用法,再去学vue-cli4,可以说是重新学vue,,,,难处大 ...
- Mockjs+Ajax实践
需要完成的工作:利用mock js随机生成数据,通过ajax请求,获取这些数据并展示在网页中. 一 mock js随机生成数据 官方文档中,Mock.mock( ),可以说是mock的精髓所在. Mo ...
- 如何在linux服务器下快速安装配置Node.js
简单粗暴,先用xshell或其他软件连接服务器 1.下载(此处版本根据官网版本自己修改) wget https://npm.taobao.org/mirrors/node/v8.9.3/node-v8 ...
- C语言编程入门题目--No.10
题目:打印楼梯,同时在楼梯上方打印两个笑脸. 1.程序分析:用i控制行,j来控制列,j根据i的变化来控制输出黑方格的个数. 2.程序源代码: #include "stdio.h" ...
- 图论--2-SAT--详解
问题描述: 现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x]AND A[y]=0.A[x] OR A[y] OR A[z]=1等,要确定A[0..N-1]的值,使得其满足所有限制关系. ...
- POJ Building a Space Station 最小生成树
Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 15664 Accepted: 6865 Description You ...
- postman(全局变量设置)
全局变量 全局变量作用于整个postman工具及所有环境 1.点击小齿轮进入到变量添加页面,点击Globals添加全局变量 2.输入变量名称和变量值 3.接口中设置变量 4.调用 Globals 变量 ...
- HTML 页面跳转的五种方法
H方法TML 页面跳转的五种方法 下面列了五个例子来详细说明,这几个例子的主要功能是:在5秒后,自动跳转到同目录下的hello.html(根据自己需要自行修改)文件.1) html的实现 <he ...