题目链接: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. pthread 读写锁

    pthread 读写锁 (Read Write Lock, rwlock) 把对共享资源的访问者分为读者和写者,读者仅仅对共享资源进行读访问,写者仅仅对共享资源进行写操作. 如果使用互斥量 mutex ...

  2. linux中常用服务的安装

    安装环境:centos7.5 配置离线yum源参考:https://blog.csdn.net/mayh554024289/article/details/54236336vi /etc/yum.co ...

  3. C++中的extern“C”

    首先引入extern"C"的官方解释 extern "C" is meant to be recognized by a C++ compiler and to ...

  4. scaffoldingTools

    脚手架工具 脚手架工具概要(前端工程化的发起者) 脚手架的本质作用:创建项目基础架构.提供项目规范和约定 相同的组织结构 相同的开发规范 相同的模块依赖 相同的工具配置 相同的基础代码 举例:IDE创 ...

  5. [SSL]在线检查服务器HTTPS安全

    https://myssl.com/ SSL/TLS安全评估报告 https://www.ssllabs.com/ssltest/ SSL Server Test HTTPS开启工具(IIS) htt ...

  6. kubernets之pod简介

    一  k8s集群里面的最小单位是pod 1.1 一个较为简单的pod的配置文件 apiverson: api的版本号 kind: 资源的种类 metadata: pod的种类等相关信息 spec: p ...

  7. 攻防世界 - Misc(一)

    base64÷4: 1.下载附件,是一个.txt文件,打开是一串字符, 666C61677B453333423746443841334238343143413936393945444442413234 ...

  8. es_python_操作

    获取es索引 https://www.itranslater.com/qa/details/2583886977221264384

  9. 扩展:Flash消息

    扩展:Flash消息 flash存值之后只能取一次 from flask import Flask,render_template,flash,get_flashed_messages,session ...

  10. js千分位分隔,数字货币化方法学习记录

    js千分位分隔,数字货币化-4种方法(含正则) 方法1-整数货币化 // 整数货币化 function intCurrency(num) { var reg = new RegExp("^[ ...