题目链接

\(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. emmc基础技术8:操作模式3-interrupt mode

    1. 前言 eMMC总线操作包含: boot mode, device identification mode interrupt mode data transfer mode 本文主要描述inte ...

  2. ARMV8 datasheet学习笔记4:AArch64系统级体系结构之存储模型

    1.前言 关于存储系统体系架构,可以概述如下: 存储系统体系结构的形式 VMSA 存储属性   2. 存储系统体系结构 2.1.    地址空间 指令地址空间溢出 指令地址计算((address_of ...

  3. mybatis学习笔记--常见的错误

    原文来自:<mybatis学习笔记--常见的错误> 昨天刚学了下mybatis,用的是3.2.2的版本,在使用过程中遇到了些小问题,现总结如下,会不断更新. 1.没有在configurat ...

  4. sql基础笔记备忘

    MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型:tinyint smallint medium ...

  5. vue修饰符学习

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. laravel 中间件

    创建中间件命令 php artisan make:middleware CheckLogin 执行完以上命令会在app/Http/Middleware目录下创建一个新的中间件类CheckLogin.p ...

  7. 性能测试四:jmeter进阶之逻辑控制器

    常用的逻辑控制器 1,循环控制器:可以设置该控制器内的sampler执行的次数,循环次数与线程的循环次数各自独立 2,if控制器:根据判断条件决定是否执行该控制器内的请求,如果是字符串比较条件,参数和 ...

  8. Python进行MySQL数据库操作

    最近开始玩Python,慢慢开始喜欢上它了,以前都是用shell来实现一些自动化或者监控的操作,现在用Python来实现,感觉更棒,Python是一门很强大的面向对象语言,所以作为一个运维DBA或者运 ...

  9. 2018-2019-2 网络对抗技术 20165333 Exp4 恶意代码分析

    2018-2019-2 网络对抗技术 20165333 Exp4 恶意代码分析 原理与实践说明 1.实践目标 监控你自己系统的运行状态,看有没有可疑的程序在运行. 分析一个恶意软件,就分析Exp2或E ...

  10. hdu 1548 升降梯

    题目大意:有一个升降机,它有两个按钮UP和DOWN,给你一些数i表示层数,并且每层对应的Ki,如果按UP按钮,会从第i层升到第i+Ki层:如果按了DOWN则会从第i层降到第i-Ki层:并规定能到的层数 ...