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