codeforces D.The Bakery
原题连接:
http://codeforces.com/contest/834/problem/D
对于前n个元素,分成k段,最大价值为 dp[n][k] :
记,区间 [i,j] 的价值为 V[i][j]
则:
dp[n][k]=maxi=0n−1(dp[i][k−1]+V[i+1][n])
对于 dp[n+1][k] 我们有:
dp[n+1][k]=maxi=0n(dp[i][k−1]+V[i+1][n+1])
影响 V[i+1][n+1] 的因素与数列中,上一次出现 an+1 的位置有关
<script type="math/tex; mode=display" id="MathJax-Element-127"></script>
_
记:上一次出现
aj
的位置为
t
那么就有:
V[i][j]=V[i][j−1]+1,其中,t<=i<j
V[i][j]=V[i][j−1],其中,0<i<t
使用区间修改线段树维护,便可缩短状态转移耗费时间。
总时间复杂度 O(nk∗log2n)
#include <algorithm>
#include <string.h>
#include <stdio.h>
#define MAXN 36000
using namespace std;
struct point
{
int c[2];
int m;//最大值
int flag;
point()
{
m=0;
c[0]=c[1]=0;
flag=0;
}
};
struct Bt
{
point A[MAXN*2];
int ma;
int deep;
int root;
int size;
void clear()
{
for(int i=0;i<deep;i++)
{
A[i].m=0;
A[i].flag=0;
A[i].c[0]=A[i].c[1]=0;
}
deep=2;
}
Bt ()
{
deep=2;
root=1;
}
void update(point &a)
{
if(A[a.c[0]].m > A[a.c[1]].m)
a.m=A[a.c[0]].m;
else
a.m=A[a.c[1]].m;
a.m+=a.flag;
}
void _add(int l,int r,int L,int R,int key,int k)
{
if(R<l||L>r)return;
if(l<=L&&R<=r)
{
if(L<R)
{
A[k].flag+=key;
A[k].m+=key;
}
else
{
A[k].m+=key;
}
return ;
}
int mid=(L+R)>>1;
if(A[k].flag>0)
{
_add(L , R , L , mid , A[k].flag , A[k].c[0]);
_add(L , R , mid+1 , R , A[k].flag , A[k].c[1]);
A[k].flag=0;
}
_add(l , r , L , mid , key , A[k].c[0]);
_add(l , r , mid+1 , R , key , A[k].c[1]);
update(A[k]);
}
void add(int l,int r,int key)
{
_add(l,r,0,size,key,root);
}
void _insert(int x,int L,int R,int key,int &k)
{
if(x<L||x>R)return;
if(!k)k=deep++;
if(L==R)
{
A[k].m=key;
return ;
}
int mid=(L+R)>>1;
_insert(x,L,mid,key,A[k].c[0]);
_insert(x,mid+1,R,key,A[k].c[1]);
update(A[k]);
}
void insert(int x,int key)
{
_insert(x,0,size,key,root);
}
void _query(int l,int r,int L,int R,int k,int key)
{
if(R<l||L>r)return ;
if(l<=L&&R<=r)
{
if(ma<A[k].m+key)
{
ma=A[k].m+key;
}
return ;
}
int mid=(L+R)>>1;
key+=A[k].flag;
_query(l , r , L , mid,A[k].c[0],key);
_query(l , r , mid+1 , R,A[k].c[1],key);
}
void query(int l,int r)
{
ma=0;
_query(l,r,0,size,root,0);
}
}B;
int A[MAXN];
int L[MAXN];
int dp[MAXN];
int C[MAXN];
int main ()
{
int n,k;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",A+i);
L[i]=C[A[i]];
C[A[i]]=i;
}
B.size=n;
for(int i=0;i<=n;i++) B.insert(i,0);
for(int i=0;i<k;i++)
{
for(int j=1;j<=n;j++)
{
B.add(L[j] , j-1 ,1);
B.query(0,j-1);
dp[j]=B.ma;
}
B.clear();
for(int j=0;j<=n;j++) B.insert(j,dp[j]);
}
printf("%d\n",dp[n]);
return 0;
}