题目链接

\(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]

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

  1. /*
  2. 592ms 8400KB
  3. 注意1.可以从f[0]更新
  4. 2.查询位置与第一层循环的关系
  5. 3.开四倍空间...
  6. 基本线段树都不会写了...
  7. */
  8. #include<cstdio>
  9. #include<cctype>
  10. #include<cstring>
  11. #include<algorithm>
  12. //#define gc() getchar()
  13. #define gc() (SS==IN &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
  14. const int N=35005,MAXIN=5e6;
  15. int n,k,A[N],f[N],las[N],tmp[N];
  16. char IN[MAXIN],*SS=IN,*TT=IN;
  17. inline int read()
  18. {
  19. int now=0;register char c=gc();
  20. for(;!isdigit(c);c=gc());
  21. for(;isdigit(c);now=now*10+c-'0',c=gc());
  22. return now;
  23. }
  24. struct Seg_Tree
  25. {
  26. int maxv[N<<2],tag[N<<2];
  27. inline void PushUp(int rt)
  28. {
  29. maxv[rt]=std::max(maxv[rt<<1],maxv[rt<<1|1]);
  30. }
  31. inline void PushDown(int rt)
  32. {
  33. maxv[rt<<1]+=tag[rt], maxv[rt<<1|1]+=tag[rt];
  34. tag[rt<<1]+=tag[rt], tag[rt<<1|1]+=tag[rt];
  35. tag[rt]=0;
  36. }
  37. void Build(int l,int r,int rt)
  38. {
  39. tag[rt]=0;
  40. if(l==r) {maxv[rt]=f[l]; return;}
  41. int m=l+r>>1;
  42. Build(l,m,rt<<1), Build(m+1,r,rt<<1|1);
  43. PushUp(rt);
  44. }
  45. void Modify(int l,int r,int rt,int L,int R)
  46. {
  47. if(L<=l && r<=R)
  48. {
  49. ++maxv[rt], ++tag[rt];
  50. return;
  51. }
  52. if(tag[rt]) PushDown(rt);
  53. int m=l+r>>1;
  54. if(L<=m) Modify(l,m,rt<<1,L,R);
  55. if(m<R) Modify(m+1,r,rt<<1|1,L,R);
  56. PushUp(rt);
  57. }
  58. int Query(int l,int r,int rt,int L,int R)
  59. {
  60. if(L<=l && r<=R) return maxv[rt];
  61. if(tag[rt]) PushDown(rt);
  62. int m=l+r>>1;
  63. if(L<=m)
  64. if(m<R) return std::max(Query(l,m,rt<<1,L,R),Query(m+1,r,rt<<1|1,L,R));
  65. else return Query(l,m,rt<<1,L,R);
  66. else return Query(m+1,r,rt<<1|1,L,R);
  67. }
  68. }t;
  69. int main()
  70. {
  71. #ifndef ONLINE_JUDGE
  72. freopen("D.in","r",stdin);
  73. #endif
  74. n=read(),k=read();
  75. for(int i=1;i<=n;++i)
  76. A[i]=read(), las[i]=tmp[A[i]], tmp[A[i]]=i;
  77. // for(int i=1;i<=n;++i) printf("%d %d\n",A[i],las[i]);
  78. for(int i=1;i<=k;++i)
  79. {
  80. t.Build(0,n,1);
  81. for(int j=i;j<=n;++j)
  82. t.Modify(0,n,1,las[j],j-1),f[j]=t.Query(0,n,1,i-1,j-1);
  83. }
  84. printf("%d",f[n]);
  85. return 0;
  86. }

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

  1. /*
  2. 624ms 9400KB 和另一个差不了多少
  3. 注意1.可以从f[0]更新
  4. 2.查询位置与第一层循环的关系
  5. */
  6. #include<cstdio>
  7. #include<cctype>
  8. #include<cstring>
  9. #include<algorithm>
  10. //#define gc() getchar()
  11. #define gc() (SS==IN &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
  12. #define lson node[rt].ls
  13. #define rson node[rt].rs
  14. const int N=35005,MAXIN=5e6;
  15. int n,k,A[N],f[N],las[N],tmp[N];
  16. char IN[MAXIN],*SS=IN,*TT=IN;
  17. inline int read()
  18. {
  19. int now=0;register char c=gc();
  20. for(;!isdigit(c);c=gc());
  21. for(;isdigit(c);now=now*10+c-'0',c=gc());
  22. return now;
  23. }
  24. struct Seg_Tree
  25. {
  26. int tot;
  27. struct Node
  28. {
  29. int ls,rs,maxv,tag;
  30. }node[N<<1];
  31. inline void PushUp(int rt)
  32. {
  33. node[rt].maxv=std::max(node[lson].maxv,node[rson].maxv);
  34. }
  35. inline void PushDown(int rt)
  36. {
  37. node[lson].maxv+=node[rt].tag, node[rson].maxv+=node[rt].tag;
  38. node[lson].tag+=node[rt].tag, node[rson].tag+=node[rt].tag;
  39. node[rt].tag=0;
  40. }
  41. void Build(int l,int r)
  42. {
  43. int p=tot++;
  44. node[p].tag=0;
  45. if(l==r) { node[p].ls=node[p].rs=-1,node[p].maxv=f[l]; return;}
  46. int m=l+r>>1;
  47. node[p].ls=tot, Build(l,m);
  48. node[p].rs=tot, Build(m+1,r);
  49. PushUp(p);
  50. }
  51. void Modify(int l,int r,int rt,int L,int R)
  52. {
  53. if(L<=l && r<=R)
  54. {
  55. ++node[rt].maxv, ++node[rt].tag;
  56. return;
  57. }
  58. if(node[rt].tag) PushDown(rt);
  59. int m=l+r>>1;
  60. if(L<=m) Modify(l,m,lson,L,R);
  61. if(m<R) Modify(m+1,r,rson,L,R);
  62. PushUp(rt);
  63. }
  64. int Query(int l,int r,int rt,int L,int R)
  65. {
  66. if(L<=l && r<=R) return node[rt].maxv;
  67. if(node[rt].tag) PushDown(rt);
  68. int m=l+r>>1;
  69. if(L<=m)
  70. if(m<R) return std::max(Query(l,m,lson,L,R),Query(m+1,r,rson,L,R));
  71. else return Query(l,m,lson,L,R);
  72. else return Query(m+1,r,rson,L,R);
  73. }
  74. }t;
  75. int main()
  76. {
  77. #ifndef ONLINE_JUDGE
  78. freopen("D.in","r",stdin);
  79. #endif
  80. n=read(),k=read();
  81. for(int i=1;i<=n;++i)
  82. A[i]=read(), las[i]=tmp[A[i]], tmp[A[i]]=i;
  83. // for(int i=1;i<=n;++i) printf("%d %d\n",A[i],las[i]);
  84. for(int i=1;i<=k;++i)
  85. {
  86. t.tot=0, t.Build(0,n);
  87. for(int j=i;j<=n;++j)
  88. t.Modify(0,n,0,las[j],j-1),f[j]=t.Query(0,n,0,i-1,j-1);
  89. }
  90. printf("%d",f[n]);
  91. return 0;
  92. }

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. 实现开发板与ubuntu的共享--根文件系统NFS--Samba共享【sky原创】

    虚拟机要选择桥接,并且禁用有线和无线网卡,开启本地连接,本地连接属性要写如下:     ip地址是在连上板子后,windows   cmd  下  ipconfig得出的 板子的网线最好连接交换机或者 ...

  2. WebsphereMQ搭建集群

    #https://www.ibm.com/developerworks/cn/websphere/library/techarticles/1202_gaoly_mq/1202_gaoly_mq.ht ...

  3. @Html.Action()

    背景 在这里主要想谈下mvc,最初几年都是用的webform,作为一个资深傻瓜程序员多年,后来到处听说mvc,终于在某天下定决心实验下mvc,其实关键还是在于easyui,因为它的请求数据方式和mvc ...

  4. quartz在application中的使用

    项目结构图: TestMain.java package com; import org.quartz.Scheduler; import org.quartz.impl.StdSchedulerFa ...

  5. python3内存存储几种数据类型对差异

    列表,元组,集合,字典几种数据类型差异 列表: list=[0,1,'a'] 元组:list=(0,1,'a') 集合 :list=[0,1,'a'] 字典:list={name:'tom',age: ...

  6. java控制语句 if-else while do-while for return break continue goto switch default

    if for //: object/ForEachFloat.java package object; import java.util.Random; public class ForEachFlo ...

  7. PHP递归排序

    递归算法对于任何一个编程人员来说,应该都不陌生.因为递归这个概念,无论是在PHP语言还是Java等其他编程语言中,都是大多数算法的灵魂. 对于PHP新手来说,递归算法的实现原理可能不容易理解.但是只要 ...

  8. 从输入url到显示网页,后台发生了什么?

    参考http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/ http://www.cnblogs.com/we ...

  9. 创建表空间tablespace,删除

    在plsql工具中执行以下语句,可建立Oracle表空间. /*分为四步 *//*第1步:创建临时表空间  */create temporary tablespace yuhang_temp temp ...

  10. bootstrap之排版样式

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