题目链接

\(Description\)

有n个数,将其分为k段,每段的值为这一段的总共数字种类,问最大总值是多少

\(Solution\)

DP,用\(f[i][j]\)表示当前在i 分成了j份(第j份包括i)

那枚举前边的断点k,即

\(f[i][j]=max{f[k][j-1]+val(k+1,1)}\)

\(val(a,b)\)表示\([a,b]\)这段区间的价值(数字种数)

\(O(n^2*k)\)

第二维可以滚动数组优化掉,只在最外层枚举即可

优化求\(val()\)的过程

val是与数的种类数有关,所以对于a[i],在计算\([1,las[a[i]]]\)的val[]时,a[i]不会做出贡献;

而用\([las[a[i]]+1,i]\)计算val时,a[i]会有1的贡献

即用\(f[k](k∈[1,\ las[a[i]]-1])\)时,不会有a[i]的贡献;

而用\(f[k](k∈[las[a[i]],\ i-1])\)更新时,a[i]会对其产生贡献(k这个点是不在后一个区间里的)

在这段区间+1,然后查询最优值,更新f[i]

区间加、区间查询最优值 -> 线段树

/*
592ms 8400KB
注意1.可以从f[0]更新
2.查询位置与第一层循环的关系
3.开四倍空间... 基本线段树都不会写了...
*/
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
//#define gc() getchar()
#define gc() (SS==IN &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=35005,MAXIN=5e6; int n,k,A[N],f[N],las[N],tmp[N];
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
struct Seg_Tree
{
int maxv[N<<2],tag[N<<2];
inline void PushUp(int rt)
{
maxv[rt]=std::max(maxv[rt<<1],maxv[rt<<1|1]);
}
inline void PushDown(int rt)
{
maxv[rt<<1]+=tag[rt], maxv[rt<<1|1]+=tag[rt];
tag[rt<<1]+=tag[rt], tag[rt<<1|1]+=tag[rt];
tag[rt]=0;
}
void Build(int l,int r,int rt)
{
tag[rt]=0;
if(l==r) {maxv[rt]=f[l]; return;}
int m=l+r>>1;
Build(l,m,rt<<1), Build(m+1,r,rt<<1|1);
PushUp(rt);
}
void Modify(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R)
{
++maxv[rt], ++tag[rt];
return;
}
if(tag[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify(l,m,rt<<1,L,R);
if(m<R) Modify(m+1,r,rt<<1|1,L,R);
PushUp(rt);
}
int Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return maxv[rt];
if(tag[rt]) PushDown(rt);
int m=l+r>>1;
if(L<=m)
if(m<R) return std::max(Query(l,m,rt<<1,L,R),Query(m+1,r,rt<<1|1,L,R));
else return Query(l,m,rt<<1,L,R);
else return Query(m+1,r,rt<<1|1,L,R);
}
}t; int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
#endif n=read(),k=read();
for(int i=1;i<=n;++i)
A[i]=read(), las[i]=tmp[A[i]], tmp[A[i]]=i;
// for(int i=1;i<=n;++i) printf("%d %d\n",A[i],las[i]);
for(int i=1;i<=k;++i)
{
t.Build(0,n,1);
for(int j=i;j<=n;++j)
t.Modify(0,n,1,las[j],j-1),f[j]=t.Query(0,n,1,i-1,j-1);
}
printf("%d",f[n]); return 0;
}

堆式存储:(多维护了ls,rs而只少了两倍空间,所以空间优化不大)(写这个纯粹闲的)

/*
624ms 9400KB 和另一个差不了多少 注意1.可以从f[0]更新
2.查询位置与第一层循环的关系
*/
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
//#define gc() getchar()
#define gc() (SS==IN &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define lson node[rt].ls
#define rson node[rt].rs
const int N=35005,MAXIN=5e6; int n,k,A[N],f[N],las[N],tmp[N];
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
struct Seg_Tree
{
int tot;
struct Node
{
int ls,rs,maxv,tag;
}node[N<<1];
inline void PushUp(int rt)
{
node[rt].maxv=std::max(node[lson].maxv,node[rson].maxv);
}
inline void PushDown(int rt)
{
node[lson].maxv+=node[rt].tag, node[rson].maxv+=node[rt].tag;
node[lson].tag+=node[rt].tag, node[rson].tag+=node[rt].tag;
node[rt].tag=0;
}
void Build(int l,int r)
{
int p=tot++;
node[p].tag=0;
if(l==r) { node[p].ls=node[p].rs=-1,node[p].maxv=f[l]; return;}
int m=l+r>>1;
node[p].ls=tot, Build(l,m);
node[p].rs=tot, Build(m+1,r);
PushUp(p);
}
void Modify(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R)
{
++node[rt].maxv, ++node[rt].tag;
return;
}
if(node[rt].tag) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify(l,m,lson,L,R);
if(m<R) Modify(m+1,r,rson,L,R);
PushUp(rt);
}
int Query(int l,int r,int rt,int L,int R)
{
if(L<=l && r<=R) return node[rt].maxv;
if(node[rt].tag) PushDown(rt);
int m=l+r>>1;
if(L<=m)
if(m<R) return std::max(Query(l,m,lson,L,R),Query(m+1,r,rson,L,R));
else return Query(l,m,lson,L,R);
else return Query(m+1,r,rson,L,R);
}
}t; int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
#endif n=read(),k=read();
for(int i=1;i<=n;++i)
A[i]=read(), las[i]=tmp[A[i]], tmp[A[i]]=i;
// for(int i=1;i<=n;++i) printf("%d %d\n",A[i],las[i]);
for(int i=1;i<=k;++i)
{
t.tot=0, t.Build(0,n);
for(int j=i;j<=n;++j)
t.Modify(0,n,0,las[j],j-1),f[j]=t.Query(0,n,0,i-1,j-1);
}
printf("%d",f[n]); return 0;
}

Codeforces.833B.The Bakery(线段树 DP)的更多相关文章

  1. CodeForces 834D The Bakery(线段树优化DP)

    Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredient ...

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

    B. The Bakery   Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought req ...

  3. Codeforces.264E.Roadside Trees(线段树 DP LIS)

    题目链接 \(Description\) \(Solution\) 还是看代码好理解吧. 为了方便,我们将x坐标左右反转,再将所有高度取反,这样依然是维护从左到右的LIS,但是每次是在右边删除元素. ...

  4. CF833B The Bakery (线段树+DP)

    题目大意:给你一个序列(n<=35000),最多分不大于m块(m<=50),求每个块内不同元素的数量之和的最大值 考试的时候第一眼建图,没建出来,第二眼贪心 ,被自己hack掉了,又随手写 ...

  5. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  6. Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)

    [题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...

  7. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  8. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  9. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

随机推荐

  1. Django 聚合与查询集API实现侧边栏

    本文从Django官方文档总结而来,将聚合的主要用法和查询集的常见方法做一归纳. 聚合 1. 聚合的产生来源于django数据库查询,通常我们使用django查询来完成增删查改,但是有时候需要更复杂的 ...

  2. linux 定期清除日志

    clearLog.sh #!/bin/sh find /usr/local/apache/logs -mtime + 30 -name "*.log" -exec rm {} \; ...

  3. C语言函数调用栈(三)

    6 调用栈实例分析 本节通过代码实例分析函数调用过程中栈帧的布局.形成和消亡. 6.1 栈帧的布局 示例代码如下: //StackReg.c #include <stdio.h> //获取 ...

  4. python根据服务名获取服务启动路径

    #coding=utf8 import _winreg as winreg class Win32Environment: """Utility class to get ...

  5. SharePoint 2013 Workflow Manager 1.0 远程服务器返回错误: (400) 错误的请求。 不支持查询字符串中的 api-version

    环境: Windows Server 2012 R2 Standard SharePoint Server 2013 with sp1 通过Web 平台安装程序 5.0,已安装 Workflow Ma ...

  6. OA系统高性能解决方案(史上最全的通达OA系统优化方案)

    序: 这是一篇针对通达OA系统的整体优化方案,文档将硬件.网络.linux操作系统.程序本身(包括web和数据库)以及现有业务有效结合在一起,进行了系统的整合优化.该方案应用于真实生产环境,部署完成后 ...

  7. centos6.5生产环境编译安装nginx-1.11.3并增加第三方模块ngx_cache_purge、nginx_upstream_check、ngx_devel_kit、lua-nginx

    1.安装依赖包 yum install -y gcc gcc-c++ pcre-devel openssl-devel geoip-devel 2.下载需要的安装包 LuaJIT-2.0.4.zip ...

  8. PYTHON-绑定方法 反射 内置函数

    '''绑定方法类中定义函数分为了两大类: 1. 绑定方法 特殊之处: 绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入 如何用: 绑定给对象的方法: 在类中定义函数没有被任何装饰器修饰 ...

  9. C <string.h>常用函数介绍

    1. strcpychar *strcpy(char *destin, char *source);功能:将source指向的字符串拷到destin. int main() { ]; "; ...

  10. java多线程快速入门(八)

    设置线程优先级:join() package com.cppdy; class MyThreadA extends Thread{ MyThreadB b; public MyThreadA(MyTh ...