【动态规划】【线段树】 Codeforces Round #426 (Div. 1) B. The Bakery

给你一个序列,让你划分成K段,每段的价值是其内部权值的种类数,让你最大化所有段的价值之和。

裸dp

f(i,j)=max{f(k,j-1)+w(k+1,i)}(0<=k<i)

先枚举j,然后枚举i的时候,用线段树进行优化,对a(i)上一次出现的位置到i之间的f(k,j-1)的答案进行+1,然后求个i的前缀max。

要注意线段树区间加的时候其实要包含上0。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
int n,m,a[35010],f[35010][60];
int maxv[35010<<2];
int delta[35010<<2];
void pushdown(int rt)//将rt结点的懒惰标记下传 
{
	if(delta[rt])
	  {
		delta[rt<<1]+=delta[rt];//标记下传到左结点 
		delta[rt<<1|1]+=delta[rt];//标记下传到右结点 
		maxv[rt<<1]+=delta[rt];
		maxv[rt<<1|1]+=delta[rt];
		delta[rt]=0;
	  }
}
void update(int ql,int qr,int v,int rt,int l,int r)
{
	if(ql<=l&&r<=qr)
	  {
		delta[rt]+=v;//更新当前结点的标记值 
		maxv[rt]+=v;
		return ;
	  }
	pushdown(rt);//将该节点的标记下传到孩子们 
	int m=(l+r)>>1;
	if(ql<=m)
	  update(ql,qr,v,lson);
	if(m<qr)
	  update(ql,qr,v,rson);
	maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
}
int query(int ql,int qr,int rt,int l,int r)
{
	if(ql<=l&&r<=qr)
	  return maxv[rt];
	pushdown(rt);//将该节点的标记下传到孩子们 
	int m=(l+r)>>1;
	int res=-2147483647;
	if(ql<=m)
	  res=max(res,query(ql,qr,lson));
	if(m<qr)
	  res=max(res,query(ql,qr,rson));
	return res;
}
int now[35010],last[35010];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;++i){
		last[i]=now[a[i]];
		now[a[i]]=i;
	}
	for(int j=1;j<=m;++j){
		if(j!=1){
			memset(maxv,0,sizeof(maxv));
			memset(delta,0,sizeof(delta));
			for(int i=j-1;i<=n;++i){
				update(i,i,f[i][j-1],1,0,n);
			}
		}
		update(max(last[j],j-1),j-1,1,1,0,n);
		f[j][j]=j;
		for(int i=j+1;i<=n;++i){
			update(max(last[i],j-1),i-1,1,1,0,n);
			f[i][j]=query(j-1,i-1,1,0,n);
		}
	}
	printf("%d\n",f[n][m]);
	return 0;
}
posted @ 2017-07-31 02:27  AutSky_JadeK  阅读(322)  评论(2编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト