Codeforces 834D The Bakery DP(线段树维护)

题意:k个盒子,n个蛋糕,第i个蛋糕为种类a[i],每次把连续一段的蛋糕装到某个盒子中.价值为该盒子里蛋糕种类不同的个数 n<=4e4,k<=50.问最大价值
设dp[i][j]:前j个蛋糕放到i个盒子中的最大价值,f(x,j)为[x,j]中蛋糕不同的个数.

dp[i][j]=max(dp[i-1][x-1]+f(x,j)) 用线段树维护dp[i-1][x-1]+f(x,j) 先把dp[i-1][1-n]插入到线段树中,随着j增加,更新f(x,j)变化的那段区间即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int n,k,p[N],last[N],a[N];
int dp[60][N],mx[N],tag[N];
void push_up(int o)
{
	mx[o]=max(mx[o<<1],mx[o<<1|1]);
}
void build(int o,int l,int r,int i)
{
	tag[o]=0;
	if(l==r)
	{
		mx[o]=dp[i-1][l-1];
		return;
	}
	int m=l+r>>1;
	build(o<<1,l,m,i);
	build(o<<1|1,m+1,r,i);
	push_up(o);
}
void push_down(int o)
{
	if(tag[o])
	{
		mx[o<<1]+=tag[o],mx[o<<1|1]+=tag[o];
		tag[o<<1]+=tag[o],tag[o<<1|1]+=tag[o];
		tag[o]=0;
	}
}
void update(int o,int l,int r,int ql,int qr,int v)
{
	if(ql<=l&&qr>=r)
	{
		mx[o]+=v;
		tag[o]+=v;
		return;
	}
	push_down(o);
	int m=l+r>>1;
	if(ql<=m)	update(o<<1,l,m,ql,qr,v);
	if(qr>m)	update(o<<1|1,m+1,r,ql,qr,v);
	push_up(o);
}
int query(int o,int l,int r,int ql,int qr)
{
	if(ql<=l&&qr>=r)
		return mx[o];
	int m=l+r>>1,res=-1e9;
	if(ql<=m)	res=max(res,query(o<<1,l,m,ql,qr));
	if(qr>m)	res=max(res,query(o<<1|1,m+1,r,ql,qr));
	return res;
}
int main()
{
	while(cin>>n>>k)
	{
		memset(last,0,sizeof(last));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			p[i]=last[a[i]];
			last[a[i]]=i;
		}
		for(int i=1;i<=n;i++)
			dp[0][i]=-1e9;
		dp[0][0]=0;
		for(int i=1;i<=k;i++)
		{
			build(1,1,n,i);	
			for(int j=1;j<=n;j++)
			{
				update(1,1,n,p[j]+1,j,1);
				dp[i][j]=query(1,1,n,1,j);
			}
		}	
		printf("%d\n",dp[k][n]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值