题目链接: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. 【剑指 Offer】08.二叉树的下一个节点

    题目描述 给定一颗二叉树和其中的一个节点,找出中序遍历序列的下一个节点.树中的节点除了有两个分别指向左右节点的指针,还有一个指向父节点的指针. Java public class Solution08 ...

  2. 【Flutter】功能型组件之异步UI更新

    前言 很多时候会依赖一些异步数据来动态更新UI,比如在打开一个页面时我们需要先从互联网上获取数据,在获取数据的过程中我们显示一个加载框,等获取到数据时我们再渲染页面:又比如想展示Stream(比如文件 ...

  3. ORA-00245 control file backup operation failed 分析和解决

    一.问题说明 操作系统: RedHat 5.8 数据库: 11.2.0.3 2节点RAC. 使用RMAN 备份的时候,报如下错误: ORA-00245: control file backup fai ...

  4. 【Oracle】 并行查询

    所谓并行执行,是指能够将一个大型串行任务(任何DML,一般的DDL)物理的划分为叫多个小的部分,这些较小的部分可以同时得到处理.何时使用并行执行:1.必须有一个非常大的任务 2.必须有充足的资源(CP ...

  5. Python利用最优化算法求解投资内部收益率IRR【一】

    一. 内部收益率和净现值 内部收益率(Internal Rate of Return, IRR)其实要和净现值(Net Present Value, NPV)结合起来讲.净现值指的是某个投资项目给公司 ...

  6. SAP里会话结束方法(杀死进程)

    在SAP的ERP里,有很多方法可以结束一个会话,然而在不同情况下,需要使用的方法也不同.下面从先后顺序来简单说明:1.SM04:最常用的方法,在SM04点击工具栏的会话->结束会话,来关闭一个会 ...

  7. Cookie&Session&Jsp总结

    知识点梳理 Cookie&Session&Jsp 1 会话技术 1.1 会话管理概述 1.1.1 会话技术介绍 会话:浏览器和服务器之间的多次请求和响应 (一次对话) 为了实现一些功能 ...

  8. Canal:同步mysql增量数据工具,一篇详解核心知识点

    老刘是一名即将找工作的研二学生,写博客一方面是总结大数据开发的知识点,一方面是希望能够帮助伙伴让自学从此不求人.由于老刘是自学大数据开发,博客中肯定会存在一些不足,还希望大家能够批评指正,让我们一起进 ...

  9. 干电池1.5V升压3.3V芯片电路图

    1.5V升压3.3V的芯片 PW5100 是一款大效率.10uA低功耗.低纹波.高工作频率1.2MHZ的 PFM 同步升压 DC/DC 变换器.输入电压可低0.7V,输入电压范围0.7V-5V之间,输 ...

  10. Netty服务端Server代码说明

    本文是简单的Netty启动服务端代码理解笔记 public class MyServer { public static void main(String[] args) throws Excepti ...