题目描述
不久前,Slastyona the Sweetmaid 决定开设自己的面包店!她买齐了所需的原料,还有一台可以烘焙多种蛋糕的奇妙烤箱,并开张了面包店。
很快,开支开始超过收入,于是 Slastyona 决定研究甜点市场。她了解到,将蛋糕装入盒子会更有利可图,而且每个盒子里不同种类蛋糕越多(我们将这个数量称为盒子的价值),价格就越高。
她需要改变生产技术!问题在于,烤箱会自行决定蛋糕的种类,Slastyona 无法干预。然而,她知道今天烤箱将要依次烘烤出 n 个蛋糕的类型和顺序。今天,Slastyona 必须准确地用 k 个盒子来打包这些蛋糕,并且每个盒子内必须放入若干(至少一个)连续烘焙出来的蛋糕(换句话说,每个盒子包含一段蛋糕的连续区间)。
Slastyona 希望最大化所有盒子的总价值。请你帮她求出所有盒子的最大可能总价值。
输入格式
第一行包含两个整数 n 和 k(1≤n≤35000,1≤k≤min(n,50))------蛋糕的数量以及盒子的数量。
第二行包含 n 个整数 a1,a2,...,an(1≤ai≤n)------按照烤箱生产顺序排列的蛋糕类型。
输出格式
输出唯一一个整数,表示所有盒子中的蛋糕最大可能的总价值。
显示翻译
题意翻译
输入输出样例
输入 #1复制
4 1
1 2 2 1
输出 #1复制
2
输入 #2复制
7 2
1 3 3 1 4 4 4
输出 #2复制
5
输入 #3复制
8 3
7 7 8 7 7 8 1 7
输出 #3复制
6
说明/提示
在第一个样例中,Slastyona 只有一个盒子。她必须把所有蛋糕都放进这个盒子里,因此这个盒子有两种类型,价值为 2。
在第二个样例中,最优策略是将前两个蛋糕放入第一个盒子,其余的都放进第二个盒子。则第一个盒子有两种类型,第二个盒子有三种类型,因此总价值为 5。
由 ChatGPT 5 翻译
代码实现;
cpp
#include<bits/stdc++.h>
#define re register
#define il inline
using namespace std;
const int N=35005;
const int M=55;
int n,k;
int a[N];
int dp[N][M];
int pre[N], pos[N];
int vis[N], p[N];
struct SegTree{
struct nd{
int l,r,v,ad;
}t[4*N];
void pd(int p){
if(t[p].ad){
int lc=p<<1, rc=p<<1|1;
t[lc].v += t[p].ad;
t[rc].v += t[p].ad;
t[lc].ad += t[p].ad;
t[rc].ad += t[p].ad;
t[p].ad = 0;
}
}
void clr(int i, int p, int l, int r){
t[p].l=l, t[p].r=r;
if(l==r){
t[p].v = dp[l][i];
return ;
}
int m=(l+r)>>1;
clr(i, p<<1, l, m);
clr(i, p<<1|1, m+1, r);
t[p].v = max(t[p<<1].v, t[p<<1|1].v);
}
void upd(int p, int l, int r, int x){
if(t[p].l>=l && t[p].r<=r){
t[p].ad += x;
t[p].v += x;
return ;
}
pd(p);
int m=(t[p].l + t[p].r)>>1;
if(l<=m) upd(p<<1, l, r, x);
if(r>m) upd(p<<1|1, l, r, x);
t[p].v = max(t[p<<1].v, t[p<<1|1].v);
}
int qry(int p, int l, int r){
if(t[p].l>=l && t[p].r<=r) return t[p].v;
pd(p);
int m=(t[p].l + t[p].r)>>1, res=0;
if(l<=m) res = qry(p<<1, l, r);
if(r>m) res = max(res, qry(p<<1|1, l, r));
return res;
}
}tr[M];
int main(){
scanf("%d %d", &n, &k);
for(int i=1;i<=n;i++){
scanf("%d", &a[i]);
pre[i] = pos[a[i]];
pos[a[i]] = i;
}
for(int i=1;i<=n;i++){
dp[i][1] = dp[i-1][1];
if(!vis[a[i]]){
vis[a[i]] = 1;
dp[i][1]++;
}
}
for(int j=2;j<=k;j++){
tr[j-1].clr(j-1, 1, 0, n);
for(int i=1;i<=n;i++){
tr[j-1].upd(1, pre[i], i-1, 1);
dp[i][j] = tr[j-1].qry(1, 0, i-1);
}
}
printf("%d", dp[n][k]);
return 0;
}