Codeforces-834D The Bakery

题目大意:将n个蛋糕装进k个盒子里,令v为每个盒子中蛋糕种类数的和,求v最大值。

最暴力的dp:f[i][j] 第i个蛋糕作为第j个盒子中最后一个的最大的v。这个复杂度显然很高,就算我们可以O(1)处理一个区间内的种类数,也需要O(n^2*k)的复杂度。显然不行。

还是观察前后转移的关系。对于每个蛋糕我们维护一个lst值,表示上一个相同的蛋糕出现的位置。那么对于每个f[i][j],我们将f[lst[i]~i-1][j-1]加一,即从后往前更新,再去f[0~i-1][j-1]的最大值即可。这个操作显然是一个区间修改+区间查询,可以用线段树实现,转移复杂度降为O(logn),是完全足够的。

为什么可行?这里f[i][j]已经脱离了之前的意思。它是动态的,即考虑到当前位置是若第i个位置装了第j个盒子的最后一个蛋糕,所可以得到的v的最大值。而这个值是随着我们从左向右遍历蛋糕而改变的。这些值得改变显然也是对后续更新无影响的。

这道题让我明白……dp居然还可以是更新已有值的。。总感觉以后遇到类似的题还是做不出来

#include
using namespace std;

#define pb push_back
#define fi first
#define se second
#define ll long long
#define pq priority_queue
#define mp make_pair
#define pii pair
#define mod 998244353
#define debug(x) cerr<<#x<<"="<=l&&cr<=r) {
			t[v][id]++;
			add[v][id]++;
			return;
		}
		int mid=cl+cr>>1;
		push_down(id,v);
		if (mid>=l) update(id,lc,cl,mid,l,r);
		if (mid=l&&cr<=r) return t[v][id];
		int mid=cl+cr>>1;
		push_down(id,v);
		int p=0,q=0;
		if (mid>=l) p=query(id,lc,cl,mid,l,r);
		if (mid>1;
		init(id,lc,l,mid);init(id,rc,mid+1,r);
		t[v][id]=max(t[lc][id],t[rc][id]);
		return;
	}
}tree;

int main(){
	scanf("%d%d",&n,&k);
	for (int i=0;i

 

你可能感兴趣的:(dp,线段树)