Description

将一个长度为n的序列分为k段

使得总价值最大一段区间的价值表示为区间内不同数字的个数

\(n\leq 35000,k\leq 50,1\leq a_i\leq n\)

Solution

定义 \(dp[i][j]\) 表示前 i 个里面分 j 段的最大收益

一个显然的 dp 方程是 \(dp[i][j]=\max \limits_{1\leq p<i} dp[p][j-1]+w(p+1,i)\)。复杂度 \(O(n^2k)\),GG。

考虑优化此方程,因为是取 max,容易想到放在线段树上实现。

同时定义 \(pre[a[i]]\) 表示当前 \(a[i]\) 这个元素上一次出现的位置是哪里,如果没有出现则是 0 。

难点在于 \(w\) 数组如何动态快速的求出来,我们外层循环一个 \(j\) 表示分的段数,发现如果当前扫到 i 这个位置那么 a[i] 的贡献实际上是让 \([pre[a[i]],i]\) 这段区间整体加一。可以这么理解,就是当前扫到 i,那么对于所有到 i 截至的区间 \([p,i]\),a[i] 这个元素对这些区间有贡献的部分是左端点\(\in [pre[a[i]],i]\) 里的这一段。线段树区间加就好了。也就是说,当前扫到了 i ,那么线段树的叶子节点 p 表示的就是 \(w[p,i]\) 的值,这也是我们用线段树的意义所在。这样就可以 \(O(nlogn)\) 求出 w 数组了。同时 dp 数组实时更新即可。

还有一点要注意的是方程是 \(dp[p][j-1]+w(p+1,i)\) ,也就是说能用来更新答案的是 节点 p 的 dp 值和 p+1 的累加值,有点麻烦,干脆把所有的 dp 值都往左挪一个就行了,也就是叶子节点 p 表示的实际上是 p+1 的值。感觉有点绕。。。

Code

#include<cstdio>
#include<cctype>
#include<cstring>
#define K 55
#define N 35005
#define min(A,B) ((A)<(B)?(A):(B))
#define max(A,B) ((A)>(B)?(A):(B))
#define swap(A,B) ((A)^=(B)^=(A)^=(B)) int n,k;
int f[N];
int val[N];
int pre[N];
int mx[N<<2];
int lazy[N<<2]; int getint(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch)) f|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
} void build(int cur,int l,int r){
if(l==r){
mx[cur]=f[l-1];
return;
}
int mid=l+r>>1;
build(cur<<1,l,mid);
build(cur<<1|1,mid+1,r);
mx[cur]=max(mx[cur<<1],mx[cur<<1|1]);
} void pushdown(int cur){
if(!lazy[cur]) return;
lazy[cur<<1]+=lazy[cur];
lazy[cur<<1|1]+=lazy[cur];
mx[cur<<1]+=lazy[cur];
mx[cur<<1|1]+=lazy[cur];
lazy[cur]=0;
} void modify(int cur,int l,int r,int ql,int qr){
if(!ql or !qr or ql>qr) return;
if(ql<=l and r<=qr){
mx[cur]++;
lazy[cur]++;
return;
}
pushdown(cur);
int mid=l+r>>1;
if(ql<=mid)
modify(cur<<1,l,mid,ql,qr);
if(mid<qr)
modify(cur<<1|1,mid+1,r,ql,qr);
mx[cur]=max(mx[cur<<1],mx[cur<<1|1]);
} int query(int cur,int l,int r,int ql,int qr){
if(ql<=l and r<=qr)
return mx[cur];
pushdown(cur);
int mid=l+r>>1,ans=0;
if(ql<=mid){
int p=query(cur<<1,l,mid,ql,qr);
ans=max(ans,p);
}
if(mid<qr){
int p=query(cur<<1|1,mid+1,r,ql,qr);
ans=max(ans,p);
}
return ans;
} signed main(){
n=getint(),k=getint();
for(int i=1;i<=n;i++)
val[i]=getint();
for(int j=1;j<=k;j++){
memset(mx,0,sizeof mx);
memset(pre,0,sizeof pre);
memset(lazy,0,sizeof lazy);
build(1,1,n);
for(int i=1;i<=n;i++){
modify(1,1,n,pre[val[i]]+1,i);
pre[val[i]]=i;
//if(i<j) continue;
f[i]=query(1,1,n,1,i);
//printf("j=%d,i=%d,f=%d\n",j,i,f[i]);
}
}
printf("%d\n",f[n]);
return 0;
}

[CF833B] The Bakery的更多相关文章

  1. CF833B The Bakery 线段树,DP

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

  2. CF-833B The Bakery(线段树优化Dp)

      Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredie ...

  3. CF833B The Bakery (线段树+DP)

    题目大意:给你一个序列(n<=35000),最多分不大于m块(m<=50),求每个块内不同元素的数量之和的最大值 考试的时候第一眼建图,没建出来,第二眼贪心 ,被自己hack掉了,又随手写 ...

  4. DP 优化方法大杂烩 & 做题记录 I.

    标 * 的是推荐阅读的部分 / 做的题目. 1. 动态 DP(DDP)算法简介 动态动态规划. 以 P4719 为例讲一讲 ddp: 1.1. 树剖解法 如果没有修改操作,那么可以设计出 DP 方案 ...

  5. Codeforeces 707B Bakery(BFS)

    B. Bakery time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...

  6. Codeforces Round #368 (Div. 2) B. Bakery (模拟)

    Bakery 题目链接: http://codeforces.com/contest/707/problem/B Description Masha wants to open her own bak ...

  7. 信号量和PV操作写出Bakery算法的同步程序

    面包店烹制面包及蛋糕,由n个销售员卖出.当有顾客进店购买面包或蛋糕时,应先在取号机上取号,然后等待叫号,若有销售员空闲时便叫下一号,试用信号量和PV操作写出Bakery算法的同步程序. 设计要求 1) ...

  8. Codeforces 834D The Bakery【dp+线段树维护+lazy】

    D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...

  9. Codeforces 834D The Bakery - 动态规划 - 线段树

    Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredient ...

随机推荐

  1. rpc和http

    rpc,远程过程调用,分布式各服务在不同的节点,因为不在同一进程中,所以节点间的调用需要通过网络进行传输,rpc是基于tcp/ip的,通过长连接进行通信.客户端需要缓存服务端的ip和端口,服务端也要缓 ...

  2. CUDA[4] sample program: matrix-vector multiplication

    Use Compressed Sparse Row Format (CSR) to represent matrix #include "cuda_runtime.h" #incl ...

  3. php判断语句

    编写代码时,可以为不同的情况执行不同的动作.可以使用判断条件语句来实现. if...else...elseif 例子一: <?php $t=date("H"); if ($t ...

  4. 秒杀系统-service

    在Dao层我们只完成了针对表的相关操作,包括写了接口方法和映射文件中的sql语句,并没有编写逻辑的代码,例如对多个Dao层方法的拼接,当我们用户成功秒杀商品时我们需要进行商品的减库存操作(调用Seck ...

  5. Maths | Metropolis-Hastings algorithm

    目录 1. 随机模拟的基本思想 2. 拒绝抽样 3. Metropolis-Hastings抽样 3.1. 引入思想 3.2. 理论基础:细致平稳条件 3.3. MH算法实现 3.4. 算法升级 3. ...

  6. shell中与C语言中的区别

    shell中为啥与C语言有区别呢?弄成一样的不是很好么,其实不然,shell提供很多操作,这些操作不单单是执行程序或者命令,在很多时候是执行脚本的,简单的shell就是脚本编程,它的主要目的是处理文件 ...

  7. 卷积在深度学习中的作用(转自http://timdettmers.com/2015/03/26/convolution-deep-learning/)

    卷积可能是现在深入学习中最重要的概念.卷积网络和卷积网络将深度学习推向了几乎所有机器学习任务的最前沿.但是,卷积如此强大呢?它是如何工作的?在这篇博客文章中,我将解释卷积并将其与其他概念联系起来,以帮 ...

  8. 背水一战 Windows 10 (65) - 控件(WebView): 对 WebView 中的内容截图, 通过 Share Contract 分享 WebView 中的被选中的内容

    [源码下载] 背水一战 Windows 10 (65) - 控件(WebView): 对 WebView 中的内容截图, 通过 Share Contract 分享 WebView 中的被选中的内容 作 ...

  9. 札记:Property动画

    简介 Android 3.0 (API level 11)引入了属性动画系统,它是一个完善的框架,可以用来对几乎任何对象进行动画.只需要指定要动画的对象属性,动画时长,属性值区间等,无论对像是否在屏幕 ...

  10. Javascript多线程

    最近项目中要用一个倒计时,但是当弹窗的时候倒计时会被阻塞,所以我想到使用Javascript多线程解决该问题. 虽然JavaScript是单线程的,但是通过worker可以让Javascript另外开 ...