CF 833B

互测题T3...

首先有个dp是非常好想的:

设dp[i][j]为前j个数分成i组的最大得分,则易得:dp[i][j]=max{dp[i-1][k-1]+num[k][j]},其中,num[k][j]表示从第k个数到第j个数不同值的数量

而num数组可以预处理出来,时间复杂度O(n^2 k)

等等,这样好像过不掉这道题啊

我们发现,max{dp[i-1][k-1]+num[k][j]}这个东西是不是应该用什么维护一下?

线段树!

利用线段树,我们可以实现区间求最值!

我们记录一个位置i上的数a[i]上一次出现的位置为las[i],那么当我们更新dp到位置i时,我们就可以进行转移,而如果一共分了k组,则最后这一组的起点一定在k以后!

同时,利用las[i],我们可以将las[i]+1~i这一整段区间的值全部+1,因为这一段区间在更新dp时不产生重复

最后我们在k~i这段区间上做区间查询,求最大值即为dp值

每次更新完一组的dp值以后,都需要重新建树,类似滚动数组的原理

还有,在建树时,考虑到转移方程中需要用到的是dp[i-1][k-1],所以在建树时赋值的下标都应当-1以便利用

代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define rt1 rt<<1
#define rt2 (rt<<1)|1
#define ls tree[rt].lson
#define rs tree[rt].rson
using namespace std;
struct Tree
{
    int lson;
    int rson;
    int maxval;
    int lazy;
}tree[400005];
int dp[55][35005];
int las[35005];
int p[35005];
int n,k;
void buildtree(int l,int r,int rt,int typ)
{
    ls=l;
    rs=r;
    tree[rt].lazy=0;
    if(l==r)
    {
        tree[rt].maxval=dp[typ][l-1];
        return;
    }
    int mid=(l+r)>>1;
    buildtree(l,mid,rt1,typ);
    buildtree(mid+1,r,rt2,typ);
    tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval);
}
void pushdown(int rt)
{
    int t=tree[rt].lazy;
    tree[rt].lazy=0;
    tree[rt1].lazy+=t;
    tree[rt2].lazy+=t;
    tree[rt1].maxval+=t;
    tree[rt2].maxval+=t;
}
void ins(int l,int r,int v,int rt)
{
    if(ls>r||rs<l)
    {
        return;
    }
    if(ls>=l&&rs<=r)
    {
        tree[rt].lazy+=v;
        tree[rt].maxval+=v;
        return;
    }
    pushdown(rt);
    int mid=(ls+rs)>>1;
    if(l<=mid)
    {
        ins(l,r,v,rt1);
    }
    if(r>mid)
    {
        ins(l,r,v,rt2);
    }
    tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval);
}
int query(int l,int r,int rt)
{
    if(l>rs||r<ls)
    {
        return 0;
    }
    if(l<=ls&&r>=rs)
    {
        return tree[rt].maxval;
    }
    pushdown(rt);
    return max(query(l,r,rt1),query(l,r,rt2));
}
int main()
{
//    freopen("handsome.in","r",stdin);
//    freopen("handsome.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        las[i]=p[x];
        p[x]=i;
    }
    buildtree(1,n,1,0);
    for(int i=1;i<=k;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int lq=las[j];
            ins(lq+1,j,1,1);
            dp[i][j]=query(i,j,1);
        }
        buildtree(1,n,1,i);
    }
    printf("%d\n",dp[k][n]);
    return 0;
}

 

posted @ 2018-10-02 09:30  lleozhang  Views(442)  Comments(0Edit  收藏  举报
levels of contents