CodeForces 834D The Bakery(dp+线段树)

The Bakery

Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredients and a wonder-oven which can bake several types of cakes, and opened the bakery.

Soon the expenses started to overcome the income, so Slastyona decided to study the sweets market. She learned it's profitable to pack cakes in boxes, and that the more distinct cake types a box contains (let's denote this number as the value of the box), the higher price it has.

She needs to change the production technology! The problem is that the oven chooses the cake types on its own and Slastyona can't affect it. However, she knows the types and order of n cakes the oven is going to bake today. Slastyona has to pack exactly k boxes with cakes today, and she has to put in each box several (at least one) cakes the oven produced one right after another (in other words, she has to put in a box a continuous segment of cakes).

Slastyona wants to maximize the total value of all boxes with cakes. Help her determine this maximum possible total value.

Input

The first line contains two integers n and k (1 ≤ n ≤ 350001 ≤ k ≤ min(n, 50)) – the number of cakes and the number of boxes, respectively.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n) – the types of cakes in the order the oven bakes them.

Output

Print the only integer – the maximum total value of all boxes with cakes.

Examples
input
Copy
4 1
1 2 2 1
output
Copy
2
input
Copy
7 2
1 3 3 1 4 4 4
output
Copy
5
input
Copy
8 3
7 7 8 7 7 8 1 7
output
Copy
6
Note

In the first example Slastyona has only one box. She has to put all cakes in it, so that there are two types of cakes in the box, so the value is equal to 2.

In the second example it is profitable to put the first two cakes in the first box, and all the rest in the second. There are two distinct types in the first box, and three in the second box then, so the total value is 5.

题意:问把这n个数分为k段后的最大权值是多少,每一段的权值就是这一段的种类数.

思路:若dp[i][j]代表把前i个分为j段的最大权值,那么dp[i][j] = max(dp[t-1][j-1]+w[t][i])(1<= t <=i),w[t][i]代表第t个到第i个的权值.

但是酱的复杂度为O(k*n^2),根本不允许.

但是我们倘若从1到k枚举分成的段数,那么分为i段能否有分为i-1段快速得来呢?假如我们知道dp[i-1][x],我们可以把dp[i]建成一个线段树,线段树底部存的就是dp[i-1][j-1],表示把前j-1分为i-1个的最大值,现在我们要求dp[i][j],也就是新加入了第j个元素,而且这个元素肯定位于第i个盒子里,那么这个元素的威力可以发挥到哪呢,当然是前一次出现这个元素的下一个位置了,我们就可以对那个位置到j位置的线段树+1.然后求1-j的最大值就是dp[i][j].时间复杂度O(k*n*log(n)).

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const double esp = 1e-12;
const int ff = 0x3f3f3f3f;
map<int,int>::iterator it;

struct tree
{
	int l,r;
	int max_v;
	int val;
	int lazy;
}e[maxn*4];

int n,m;
int a[maxn],pre[maxn],last[maxn],dp[maxn];

void build(int i,int l,int r)
{
	e[i].l = l;
	e[i].r = r;
	e[i].max_v = e[i].lazy = 0;
	if(l == r)
	{
		e[i].val = e[i].max_v = a[l];
		return ;
	}
	int mid = (l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	e[i].max_v = max(e[i<<1].max_v,e[i<<1|1].max_v);
}

void push_down(int i)
{
	int v = e[i].lazy;
	e[i<<1].lazy+= v;
	e[i<<1|1].lazy+= v;
	e[i<<1].max_v+= v;
	e[i<<1|1].max_v+= v;
	e[i].lazy = 0;
}

void update(int i,int l,int r,int v)
{
	if(e[i].l> r||e[i].r< l)
		return ;
	if(e[i].l>= l&&e[i].r<= r)
	{
		e[i].lazy+= v;
		e[i].max_v+= v;
		return ;
	}
	push_down(i);
	update(i<<1,l,r,v);
	update(i<<1|1,l,r,v);
	e[i].max_v = max(e[i<<1].max_v,e[i<<1|1].max_v);
}

int query(int i,int l,int r)
{
	if(e[i].l> r||e[i].r< l)
		return 0;
	if(e[i].l>= l&&e[i].r<= r)
		return e[i].max_v;
	return max(query(i<<1,l,r),query(i<<1|1,l,r));
}

int main()
{
	cin>>n>>m;
	for(int i = 1;i<= n;i++)
		scanf("%d",&a[i]);
	
	for(int i = 1;i<= n;i++)
		pre[i] = last[a[i]]+1,last[a[i]] = i;
	for(int i = 1;i<= n;i++)
		dp[i] = dp[i-1]+(pre[i] == 1);
	
	for(int i = 2;i<= m;i++)
	{
		for(int j = 1;j<= n;j++)
			a[j] = dp[j-1];
		build(1,1,n);
		for(int j = 1;j<= n;j++)
		{
			update(1,pre[j],j,1);
			dp[j] = query(1,1,j);
		}
	}
	
	cout<<dp[n]<<endl;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nka_kun/article/details/80588422
今日推荐