码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces#426(div1) B - The Bakery (线段树 + dp)

时间:2017-08-02 22:16:13      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:scanf   表示   printf   define   线段树   hash   void   string   size   

题意:把 n 个数划分成 m 段,要求每组数不相等的数的数量最大之和。

思路:

dp方程 : dp[i][j] = max( dp[k][j-1] + v(k, i) );( j<=k<i , k = j, j+1, +...+ i-1)

dp[i][j]表示第 i 个数分到第 j 段的最大值。

v(k, i) 表示k~i中不同数的个数,此处用hash记录每个数上一次出现的位置,从上一次出现的位置到当前位置的 dp[i][j-1] 值均可+1。

此时时间复杂度 O(n*m*log(n))。

线段树优化:维护 dp[k~i][j-1]的最大值。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 35010, maxk = 55, INF = 0x3f3f3f3f;

int a[maxn], dp[maxn][maxk], last[maxn], now[maxn];
int maxv[maxn<<2], lazy[maxn<<2];

push_down(int rt)
{
    if(lazy[rt])
    {
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        maxv[rt<<1]+=lazy[rt];
        maxv[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}

push_up(int rt)
{
    maxv[rt]=max(maxv[rt<<1], maxv[rt<<1|1]);
}

void update(int l, int r, int rt, int ul, int ur, int v)
{
    if(ul<=l && r<=ur)
    {
        maxv[rt]+=v;
        lazy[rt]+=v;
        return;
    }
    push_down(rt);
    int m=(l+r)/2;
    if(ul<=m) update(lson, ul, ur, v);
    if(m<ur) update(rson, ul, ur, v);
    push_up(rt);
}

int query(int l, int r, int rt, int ql, int qr)
{
    if(ql<=l && r<=qr)
        return maxv[rt];
    push_down(rt);
    int m=(l+r)/2, res=-INF;
    if(ql<=m) res=max(res, query(lson, ql, qr));
    if(qr>m) res=max(res, query(rson, ql, qr));
    push_up(rt);
    return res;
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; ++i)
        scanf("%d", &a[i]);
    for(int i=1; i<=n; ++i)
    {
        last[i]=now[a[i]];
        now[a[i]]=i;
    }
    for(int j=1; j<=m; ++j)
    {
        if(j!=1)
        {
            memset(maxv, 0, sizeof maxv);
            memset(lazy, 0, sizeof lazy);
            for(int i=j-1; i<=n; ++i)
            {
                update(0, n, 1, i, i, dp[i][j-1]);
            }
        }
        update(0, n, 1, max(j-1, last[j]), j-1, 1);
        dp[j][j]=j;
        for(int i=j+1; i<=n; ++i)
        {
            update(0, n, 1, max(j-1, last[i]), i-1, 1);
            dp[i][j]=query(0, n, 1, j-1, i-1);
        }
    }
    printf("%d\n", dp[n][m]);
    return 0;
}

 

codeforces#426(div1) B - The Bakery (线段树 + dp)

标签:scanf   表示   printf   define   线段树   hash   void   string   size   

原文地址:http://www.cnblogs.com/xiepingfu/p/7276859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!