codeforces D.The Bakery

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=0n1(dp[i][k1]+V[i+1][n])

对于 dp[n+1][k] 我们有:

dp[n+1][k]=maxi=0n(dp[i][k1]+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][j1]+1,t<=i<j

V[i][j]=V[i][j1],0<i<t

使用区间修改线段树维护,便可缩短状态转移耗费时间。
总时间复杂度 O(nklog2n)
#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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值