Codeforces.833B.The Bakery(线段树 DP)
\(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)的更多相关文章
- CodeForces 834D The Bakery(线段树优化DP)
Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredient ...
- 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 ...
- Codeforces.264E.Roadside Trees(线段树 DP LIS)
题目链接 \(Description\) \(Solution\) 还是看代码好理解吧. 为了方便,我们将x坐标左右反转,再将所有高度取反,这样依然是维护从左到右的LIS,但是每次是在右边删除元素. ...
- CF833B The Bakery (线段树+DP)
题目大意:给你一个序列(n<=35000),最多分不大于m块(m<=50),求每个块内不同元素的数量之和的最大值 考试的时候第一眼建图,没建出来,第二眼贪心 ,被自己hack掉了,又随手写 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
- Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
[题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...
- HDU 3016 Man Down (线段树+dp)
HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- Buses and People CodeForces 160E 三维偏序+线段树
Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...
- CodeForces 877E DFS序+线段树
CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...
随机推荐
- emmc基础技术8:操作模式3-interrupt mode
1. 前言 eMMC总线操作包含: boot mode, device identification mode interrupt mode data transfer mode 本文主要描述inte ...
- ARMV8 datasheet学习笔记4:AArch64系统级体系结构之存储模型
1.前言 关于存储系统体系架构,可以概述如下: 存储系统体系结构的形式 VMSA 存储属性 2. 存储系统体系结构 2.1. 地址空间 指令地址空间溢出 指令地址计算((address_of ...
- mybatis学习笔记--常见的错误
原文来自:<mybatis学习笔记--常见的错误> 昨天刚学了下mybatis,用的是3.2.2的版本,在使用过程中遇到了些小问题,现总结如下,会不断更新. 1.没有在configurat ...
- sql基础笔记备忘
MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型:tinyint smallint medium ...
- vue修饰符学习
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- laravel 中间件
创建中间件命令 php artisan make:middleware CheckLogin 执行完以上命令会在app/Http/Middleware目录下创建一个新的中间件类CheckLogin.p ...
- 性能测试四:jmeter进阶之逻辑控制器
常用的逻辑控制器 1,循环控制器:可以设置该控制器内的sampler执行的次数,循环次数与线程的循环次数各自独立 2,if控制器:根据判断条件决定是否执行该控制器内的请求,如果是字符串比较条件,参数和 ...
- Python进行MySQL数据库操作
最近开始玩Python,慢慢开始喜欢上它了,以前都是用shell来实现一些自动化或者监控的操作,现在用Python来实现,感觉更棒,Python是一门很强大的面向对象语言,所以作为一个运维DBA或者运 ...
- 2018-2019-2 网络对抗技术 20165333 Exp4 恶意代码分析
2018-2019-2 网络对抗技术 20165333 Exp4 恶意代码分析 原理与实践说明 1.实践目标 监控你自己系统的运行状态,看有没有可疑的程序在运行. 分析一个恶意软件,就分析Exp2或E ...
- hdu 1548 升降梯
题目大意:有一个升降机,它有两个按钮UP和DOWN,给你一些数i表示层数,并且每层对应的Ki,如果按UP按钮,会从第i层升到第i+Ki层:如果按了DOWN则会从第i层降到第i-Ki层:并规定能到的层数 ...