题目链接:https://vjudge.net/problem/CodeForces-833B

题意:
给长度为n的数组a,和一个整数k
要求把数组分成连续的k段,每段的权值是该段中不同数的个数,
输出最大权值和。
数据范围:n<=35000,k<=min(n,50),1<=a(i)<=n

题解:
很容易想到暴力dp的方式
dp[i][j]:前1-i个数分成了j个段
那么dp[i][j]=max(dp[k][j-1]+val[k+1][i]) //val[i][j]表示区间i-j中不同数的个数
这个方法的复杂度就是O(n^2*k),很显然不可行

那么我们可以把找max(dp[k][j-1]+val[k+1][i])这个过程使用线段树优化掉
我们可以从1-n的数分成j段建立一颗线段树,也就是对dp[x][j](1<=x<=n)建一颗线段树维护这n个数的最大值
然后对dp[i][j]的求解可以从维护dp[x][j-1]这一颗树中查找区间【1,(i-1)】的最大值

但是有一点不对,因为dp[i][j]由dp[k][j-1]和val[k+1][i]两部分构成,所以只有dp[k][j-1]最大并不一定可以得到
dp[i][j]最大,所以我们就要想办法处理一下维护dp[x][j]的线段树,让线段树维护这两部分的和

对于下面的一组数(下标从1开始)
7 8 1 7
第二个7的有效区域是[2,4],那么我们可以在原有维护dp[x][j]的线段树基础上,线段树在[2,4]这个区间的值都加1
这样的话就相当于让线段树维护了两部分的和


/*
题意:
给长度为n的数组a,和一个整数k
要求把数组分成连续的k段,每段的权值是该段中不同数的个数,
输出最大权值和。
数据范围:n<=35000,k<=min(n,50),1<=a(i)<=n 题解:
很容易想到暴力dp的方式
dp[i][j]:前1-i个数分成了j个段
那么dp[i][j]=max(dp[k][j-1]+val[k+1][i]) //val[i][j]表示区间i-j中不同数的个数
这个方法的复杂度就是O(n^2*k),很显然不可行 那么我们可以把找max(dp[k][j-1]+val[k+1][i])这个过程使用线段树优化掉
我们可以从1-n的数分成j段建立一颗线段树,也就是对dp[x][j](1<=x<=n)建一颗线段树维护这n个数的最大值
然后对dp[i][j]的求解可以从维护dp[x][j-1]这一颗树中查找区间【1,(i-1)】的最大值 但是有一点不对,因为dp[i][j]由dp[k][j-1]和val[k+1][i]两部分构成,所以只有dp[k][j-1]最大并不一定可以得到
dp[i][j]最大,所以我们就要想办法处理一下维护dp[x][j]的线段树,让线段树维护这两部分的和 对于下面的一组数(下标从1开始)
7 8 1 7
第二个7的有效区域是[2,4],那么我们可以在原有维护dp[x][j]的线段树基础上,线段树在[2,4]这个区间的值都加1
这样的话就相当于让线段树维护了两部分的和 */ #include <cstdio>
#include <cstring>
#include <iostream>
#include<algorithm>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
const int mod=1000000007;
const int INF=0x3f3f3f3f;
const long long ll_INF=0x3f3f3f3f3f3f3f3fll;
int tree[maxn<<2],dp[maxn][55],v[maxn],pre[maxn],mark[maxn],lazy[maxn<<2];
void push_up(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int rt,int L,int R,int x)
{
tree[rt]=lazy[rt]=0;
if(L==R)
{ //对于dp[j][i]的值由dp[k][i]+val[k+1][j]得到,且要保证k<j,所以用dp[L-1][x-1]来给第L位置赋值
tree[rt]=dp[L-1][x-1]; //给n个节点赋初始值
return;
}
int mid=(L+R)>>1;
build(rt<<1,L,mid,x);
build(rt<<1|1,mid+1,R,x);
push_up(rt);
}
void push_down(int rt)
{
if(lazy[rt])
{
lazy[rt<<1]+=lazy[rt]; //上一个节点的lazy值保存的是它子节点的偏移量
lazy[rt<<1|1]+=lazy[rt];
tree[rt<<1]+=lazy[rt];
tree[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}
void update(int rt,int L,int R,int LL,int RR)
{
if(LL<=L && RR>=R)
{
lazy[rt]++;
tree[rt]++;
return ;
}
push_down(rt);
int mid=(L+R)/2;
if(LL<=mid)update(rt<<1,L,mid,LL,RR);
if(RR>mid)update(rt<<1|1,mid+1,R,LL,RR);
push_up(rt);
}
int query(int rt,int L,int R,int LL,int RR)
{
if(LL<=L && RR>=R)
{
return tree[rt];
}
push_down(rt);
int mid=(L+R)>>1,ans=0;
if(LL<=mid) ans=max(ans,query(rt<<1,L,mid,LL,RR));
if(RR>mid) ans=max(ans,query(rt<<1|1,mid+1,R,LL,RR));
return ans;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; ++i)
scanf("%d",&v[i]);
for(int i=1; i<=n; ++i)
{
pre[i]=mark[v[i]]+1;
mark[v[i]]=i;
}
for(int i=1; i<=k; ++i)
{
build(1,1,n,i);
for(int j=1; j<=n; ++j)
{
update(1,1,n,pre[j],j);
dp[j][i]=query(1,1,n,1,j);
}
}
printf("%d\n",dp[n][k]);
return 0;
}

CodeForces833 B. The Bakery 线段树维护dp的更多相关文章

  1. Codeforces Round #271 (Div. 2) E题 Pillars(线段树维护DP)

    题目地址:http://codeforces.com/contest/474/problem/E 第一次遇到这样的用线段树来维护DP的题目.ASC中也遇到过,当时也非常自然的想到了线段树维护DP,可是 ...

  2. codeforces Good bye 2016 E 线段树维护dp区间合并

    codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...

  3. Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake 线段树维护dp

    D. Babaei and Birthday Cake 题目连接: http://www.codeforces.com/contest/629/problem/D Description As you ...

  4. CF833B The Bakery 线段树,DP

    CF833B The Bakery LG传送门 线段树优化DP. 其实这是很久以前就应该做了的一道题,由于颓废一直咕在那里,其实还是挺不错的一道题. 先考虑\(O(n^2k)\)做法:设\(f[i][ ...

  5. Codeforces GYM 100114 D. Selection 线段树维护DP

    D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descriptio ...

  6. 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】

    题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...

  7. 2019牛客暑期多校训练营(第二场)E 线段树维护dp转移矩阵

    题意 给一个\(n\times m\)的01矩阵,1代表有墙,否则没有,每一步可以从\(b[i][j]\)走到\(b[i+1][j]\),\(b[i][j-1]\),\(b[i][j+1]\),有两种 ...

  8. Codeforces750E. New Year and Old Subsequence (线段树维护DP)

    题意:长为2e5的数字串 每次询问一个区间 求删掉最少几个字符使得区间有2017子序列 没有2016子序列 不合法输出-1 题解:dp i,p(0-4)表示第i个数匹配到2017的p位置删掉的最少数 ...

  9. hdu4719 Oh My Holy FFF 线段树维护dp

    题意:给你一个长度为n的数组v,你需要把这个数组分成很多段,你需要保证每一段的长度不能超过k我们设一共有m段,每一段右边界那个数为bi那么我们要使得sum(bi*bi-b(i-1))最大 (1< ...

随机推荐

  1. 【Java基础】面向对象中

    面向对象中 这一章主要涉及面向对象的三大特征,包括封装.继承.多态.(抽象). 封装 程序设计追求"高内聚,低耦合": 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉: 低 ...

  2. [从源码学设计]蚂蚁金服SOFARegistry之续约和驱逐

    [从源码学设计]蚂蚁金服SOFARegistry之续约和驱逐 目录 [从源码学设计]蚂蚁金服SOFARegistry之续约和驱逐 0x00 摘要 0x01 业务范畴 1.1 失效剔除 1.2 服务续约 ...

  3. Fail2ban工具使用

    Fail2ban ​ fail2ban扫描日志文件并且可以识别禁用某些多次尝试登录的IP,通过更新系统的防火墙规则来实现拒绝该IP连接,也可以配置禁用的时间.fail2ban提供了一些常用软件默认的日 ...

  4. 【Problem】前端项目运行:Module build failed:Error Node Sass does not yet support my current environmen

    我在运行renren-fast-vue前端项目时,安装完依赖cnpm install 启动服务npm run dev 出现问题. Module build failed: Error: Node Sa ...

  5. CentOS 7 下安装 mysql ,以及用到的命令

    VMware虚拟机装好后,再装个CentOS7系统,以上环境自行百度... 一.Linux下查看mysql是否安装 1.指令ps -ef|grep mysql [root@localhost 桌面]# ...

  6. 从synchronized和lock区别入手聊聊java锁机制

    写这篇文章之前,我去百度了一下啥叫锁,百度百科上写道:置于可启闭的器物上,以钥匙或暗码开启.确实我们一般理解的锁就是门锁,密码锁,但是在计算机科学中,锁又是啥,说实话,这个问题我也思考了很久,也没法很 ...

  7. Rancher On K3s 高可用架构部署

    Rancher 推荐部署架构 k3s 模式 RKE 和 k8s 模式 备注: 我对 RKE 的理解就是 Ansible + kubeadm 的打包,首先 rke 需要到每一个节点都可以免密 ssh , ...

  8. 【Android初级】如何动态添加菜单项(附源码+避坑)

    我们平时在开发过程中,为了灵活多变,除了使用静态的菜单,还有动态添加菜单的需求.今天要分享的功能如下: 在界面的右上角有个更多选项,点开后,有两个子菜单:关于和退出 点击"关于", ...

  9. epoll在fork子进程中的问题

    epoll_create 创建的 文件描述符和其他文件描述符一样,是被fork出的子进程继承的,那也就是子进程可以使用这个epoll fd添加感兴趣的io(epoll_ctl),然后是可以影响到父进程 ...

  10. 3分钟搞懂什么是WPF。

    先推荐下猛哥(刘铁猛)的书籍  <深入浅出WPF>. 一直以来,完美的用户体验是桌面应用程序和Web应用程序中的一大障碍.许多开发人员绞尽脑汁将界面设计得美观炫丽些.互 动感强些,但费了九 ...