题意:
Slastyona开了一个蛋糕店,她发现把蛋糕装进盒子里可以盈利,且一个盒子里装的蛋糕种类越多,就可以卖的越贵。 题目规定一个盒子的价值为其中装蛋糕的种类。 她今天需要让k个盒子中被装上蛋糕,而且她的盒子不能为空。 装的蛋糕必须是取自一个连续的区间。 Slastyona希望最大化所有蛋糕盒的总价值。帮助她确定这个可能的最大值。
输入格式: 第一行包含两个正整数n,k,分别代表蛋糕的个数和盒子的个数。 第二行包含n个正整数,第i个数代表第i个蛋糕的类别
输出格式: 一个正整数,代表盒子的总价值。
范围: 保证n∈[1,35000]且为整数,k∈[1,min(n,50)]且为整数。 保证蛋糕的总种类数∈[1,n]且为整数。
\(f_{i,j}\) 表示前 \(i\) 个数分割 \(j\) 次所产生的最大值
那么很显然的一个区间dp,\(col_{i,j}\) 表示 \([i,j]\) 中不同的种类数
\[f_{i,j}=\max\{ f_{k,j-1}+col_{k+1,i} \} \]
那么显然这个是 \(O(kn^2)\) 的,过不了
我们可以考虑使用线段树优化,大概思想就是一个蛋糕能造成贡献的区间是它的位置到上一个和它种类相同的位置+1这段区间,然后就可以使用线段树优化
可以去看这篇洛谷大佬的题解,里面讲的很详细
// This code Write By chtholly_micromaker(MicroMaker)
#include <cstdio>
#include <cctype>
#include <iostream>
#include <cstring>
#define reg register
using namespace std;
const int MaxN=35005;
const int MaxK=55;
struct Node
{
int val,lazy;
};
template <class t> inline void rd(t &s)
{
s=0;
reg char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
s=(s<<3)+(s<<1)+(c^48),c=getchar();
return;
}
int pre[MaxN],pos[MaxN];
int f[MaxK][MaxN];
struct SegTree
{
#define rt (u>>1)
#define lson (u<<1)
#define rson (u<<1|1)
Node tr[MaxN<<2];
inline void clear()
{
memset(tr,0,sizeof tr);
return;
}
inline void pushup(int u)
{
tr[u].val=max(tr[lson].val,tr[rson].val);
return;
}
inline void pushdown(int u,int l,int r)
{
if(tr[u].lazy)
{
tr[lson].lazy+=tr[u].lazy;
tr[rson].lazy+=tr[u].lazy;
tr[lson].val+=tr[u].lazy;
tr[rson].val+=tr[u].lazy;
tr[u].lazy=0;
}
return;
}
inline void buildtr(int u,int l,int r,int x)
{
if(l==r)
{
tr[u].val=f[x][l-1];
return;
}
reg int mid=(l+r)>>1;
buildtr(lson,l,mid,x);
buildtr(rson,mid+1,r,x);
pushup(u);
return;
}
inline void change(int u,int l,int r,int ql,int qr,int x)
{
if(ql<=l&&r<=qr)
{
tr[u].val+=x;
tr[u].lazy+=x;
return;
}
pushdown(u,l,r);
reg int mid=(l+r)>>1;
if(ql<=mid)
change(lson,l,mid,ql,qr,x);
if(mid<qr)
change(rson,mid+1,r,ql,qr,x);
pushup(u);
return;
}
inline int query(int u,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
return tr[u].val;
pushdown(u,l,r);
reg int mid=(l+r)>>1,res=0;
if(ql<=mid)
res=max(res,query(lson,l,mid,ql,qr));
if(mid<qr)
res=max(res,query(rson,mid+1,r,ql,qr));
return res;
}
#undef rt
#undef lson
#undef rson
}segtr;
signed main(void)
{
int n,k;
reg int x;
rd(n);rd(k);
for(int i=1;i<=n;++i)
{
rd(x);
pre[i]=pos[x]+1;
pos[x]=i;
}
for(int i=1;i<=k;++i)
{
segtr.clear();
segtr.buildtr(1,1,n,i-1);
for(int j=1;j<=n;++j)
{
segtr.change(1,1,n,pre[j],j,1);
f[i][j]=segtr.query(1,1,n,1,j);
}
}
printf("%d\n",f[k][n]);
return 0;
}