传送门

线段树优化dpdpdp入门题。

要求把nnn个数分成kkk段,每段价值为里面不相同的数的个数,求所有段的价值之和最大值。n≤35000,k≤50n\le35000,k\le50n≤35000,k≤50


先考虑直接暴力dpdpdp,fj,if_{j,i}fj,i​表示把前iii个分成jjj组的最优值。

显然fj,i=max⁡j−1≤k≤i−1{fj−1,k+W(k+1,i)}f_{j,i}=\max\limits_{j-1\le k\le i-1}\{f_{j-1,k}+W(k+1,i)\}fj,i​=j−1≤k≤i−1max​{fj−1,k​+W(k+1,i)}

于是就有了一个O(n2k)O(n^2k)O(n2k)的做法。

现在考虑优化求fj,i+W(k+1,i)f_{j,i}+W(k+1,i)fj,i​+W(k+1,i)的做法。

我们考虑增量法,即枚举当前层的iii的时候考虑coloricolor_icolori​对之前所有的fff的贡献。

对于这种相同颜色只考虑一次贡献的题有这么一个固定的套路:我们记当前颜色上一次出现的位置为pre,则这个颜色会对[pre+1,i]或者[pre,i-1]这一段产生贡献

对于这道题可以动态维护fj−1,k+W(k+1,j)f_{j-1,k}+W(k+1,j)fj−1,k​+W(k+1,j)这个值,因此我们最开始将fj−1,if_{j-1,i}fj−1,i​全部放到一棵线段树上面作为初始值,走到位置iii时把[prei,i−1][pre_i,i-1][prei​,i−1]维护的值全部加111即可。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=35005,K=55;
int tmp=0,a[N],f[2][N],n,k,pre[N],mp[N];
namespace SGT{
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid (l+r>>1)
	int mx[N<<2],add[N<<2];
	inline void pushup(int p){mx[p]=max(mx[lc],mx[rc]);}
	inline void pushnow(int p,int v){mx[p]+=v,add[p]+=v;}
	inline void pushdown(int p){if(add[p])pushnow(lc,add[p]),pushnow(rc,add[p]),add[p]=0;}
	inline void build(int p,int l,int r){
		add[p]=0;
		if(l==r){mx[p]=f[tmp^1][l];return;}
		build(lc,l,mid),build(rc,mid+1,r),pushup(p);
	}
	inline void update(int p,int l,int r,int ql,int qr,int v){
		if(ql>qr)return;
		if(ql<=l&&r<=qr)return pushnow(p,v);
		pushdown(p);
		if(qr<=mid)update(lc,l,mid,ql,qr,v);
		else if(ql>mid)update(rc,mid+1,r,ql,qr,v);
		else update(lc,l,mid,ql,mid,v),update(rc,mid+1,r,mid+1,qr,v);
		pushup(p);
	}
	inline int query(int p,int l,int r,int ql,int qr){
		if(ql>qr)return -0x3f3f3f3f;
		if(ql<=l&&r<=qr)return mx[p];
		pushdown(p);
		if(qr<=mid)return query(lc,l,mid,ql,qr);
		if(ql>mid)return  query(rc,mid+1,r,ql,qr);
		return max(query(lc,l,mid,ql,mid),query(rc,mid+1,r,mid+1,qr));
	}
	#undef lc
	#undef rc
	#undef mid
}
int main(){
	n=read(),k=read();
	memset(mp,-1,sizeof(mp));
	for(ri i=1;i<=n;++i)a[i]=read(),pre[i]=mp[a[i]],mp[a[i]]=i;
	memset(f[tmp],-0x3f,sizeof(f[tmp]));
	f[tmp][0]=0;
	for(ri tt=1;tt<=k;++tt){
		tmp^=1;
		memset(f[tmp],-0x3f,sizeof(f[tmp]));
		SGT::build(1,0,n);
		for(ri i=1;i<=n;++i){
			SGT::update(1,0,n,pre[i],i-1,1);
			f[tmp][i]=SGT::query(1,0,n,tt-1,i-1);
		}
	}
	cout<<f[tmp][n];
	return 0;
}

2019.03.09 codeforces833B. The Bakery(线段树优化dp)的更多相关文章

  1. CodeForces 834D The Bakery(线段树优化DP)

    Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredient ...

  2. Codeforces Round #426 (Div. 2) D. The Bakery 线段树优化DP

    D. The Bakery   Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought req ...

  3. CF833B The Bakery 线段树,DP

    CF833B The Bakery LG传送门 线段树优化DP. 其实这是很久以前就应该做了的一道题,由于颓废一直咕在那里,其实还是挺不错的一道题. 先考虑\(O(n^2k)\)做法:设\(f[i][ ...

  4. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  5. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  6. BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】

    BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...

  7. [AGC011F] Train Service Planning [线段树优化dp+思维]

    思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...

  8. 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

    题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...

  9. POJ 2376 Cleaning Shifts (线段树优化DP)

    题目大意:给你很多条线段,开头结尾是$[l,r]$,让你覆盖整个区间$[1,T]$,求最少的线段数 题目传送门 线段树优化$DP$裸题.. 先去掉所有能被其他线段包含的线段,这种线段一定不在最优解里 ...

随机推荐

  1. Jacobian矩阵、Hessian矩阵和Newton's method

    在寻找极大极小值的过程中,有一个经典的算法叫做Newton's method,在学习Newton's method的过程中,会引入两个矩阵,使得理解的难度增大,下面就对这个问题进行描述. 1, Jac ...

  2. 并发系列2:Java并发的基石,volatile关键字、synchronized关键字、乐观锁CAS操作

    由并发大师Doug Lea操刀的并发包Concurrent是并发编程的重要包,而并发包的基石又是volatile关键字.synchronized关键字.乐观锁CAS操作这些基础.因此了解他们的原理对我 ...

  3. 前端(HTML)初始

    一.用socket实现HTML的原理 import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen() while ...

  4. WEB的数据交互具体流程

    前一段时间小小的总结了一下,web的前后交互的各种方式可能没写全,后期再写,话不多说 前端传递数据到servlet,servlet获取数据后操作DAO修改数据库,然后servlet将某些参数返回到前端 ...

  5. css,html备忘录

    1.background:url()#000 ;代表当图片不够充满容器时,用黑色填满. 2.height:inherit;继承父级元素的高度. 当子元素给了绝对定位,父元素不给相对定位,子元素也能适配 ...

  6. spark on yarn 内存分配

    Spark On YARN内存分配 本文主要了解Spark On YARN部署模式下的内存分配情况,因为没有深入研究Spark的源代码,所以只能根据日志去看相关的源代码,从而了解“为什么会这样,为什么 ...

  7. Makefile 命令解析

    1.$(patsubst %.c,%.o, a.c b.c) 把字串“a.c b.c”符合模式[%.c]的单词替换成[%.o],返回结果是“a.o b.o” 2.$(VAR:A=B) 对于一个已经定义 ...

  8. k8s中yaml文常见语法

    在k8s中,所有的配置都是 json格式的.但为了读写方便,通常将这些配置写成yaml 格式,其运行的时候,还是会靠yaml引擎将其转化为json,apiserver 也仅接受json的数据类型. y ...

  9. 【转】重写Equals为什么要同时重写GetHashCode

    .NET程序员都知道,如果我们重写一个类的Equals方法而没有重写GetHashCode,则VS会提示警告 :“***”重写 Object.Equals(object o)但不重写 Object.G ...

  10. mysql 函数介绍

    含义 一组预先编译好的SQL语句集合,可以理解成批处理语句 提高代码的重用性 简化操作 减少了编译次数并且减少了和数据库服务器的连接次数, 提高了效率 区别 : 存储过程:可以有0个返回,也可以有多个 ...