Codeforces Round #426 (Div. 1) B. The Bakery (DP + 线段树)
来源:互联网 发布:网络推手立二拆四 编辑:程序博客网 时间:2024/06/04 01:19
Problem
将 N 长序列划分 K 块的最大价值和。每块的价值定义为该段区间内的不同数的个数。
其中 N 长序列的每个数为
Limit
Idea
从数据限制来看,此题的复杂度一般应该在
普遍的第一想法是 DP(也确实是 DP)。dp[i][k]
表示将前 i 个数共划分为 k 块的最大价值。
则状态转移为: dp[i][k] = max(dp[i][k], dp[j][k-1] + distinct(j+1, i)) (1<=j<i)
如何统计 distinct (j+1, i)
是这个转移方程的最大难点。
预处理每个位置数字的前一个相同数的位置 pre[i]
。当统计分块为 k 时的所有前置状态均为 k-1 块。统计 distinct (j+1, i)
可以通过与 dp[i][k]
的 i 同步递增来达到 pre[i]
,所有的 dp[j][k-1]
(
对于这部分的 dp[j][k-1]
利用区间最大值线段树维护 update(pre[i], i-1, +1)
并查找 [1, i-1]
内的最大值即 dp[i][k]
的最大价值和。
Code
#include<bits/stdc++.h>using namespace std;const int N = 35000 + 10;const int K = 50 + 10;int n, k, a[N], pre[N], vis[N], dp[N][K];// Segment Tree #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int MAXN = 35000 + 10;int add[MAXN<<2], mx[MAXN<<2];void PushUp(int rt) { mx[rt] = max(mx[rt<<1], mx[rt<<1|1]); }void PushDown(int rt, int m) { if(add[rt]) { add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; mx[rt<<1] += add[rt]; mx[rt<<1|1] += add[rt]; add[rt] = 0; }}void build(int l, int r, int rt, int ik) { add[rt] = 0; if(l == r) { mx[rt] = dp[l][ik]; return; } int m = (l+r)>>1; build(lson, ik); build(rson, ik); PushUp(rt);}void update(int L, int R, int w, int l, int r, int rt) { if(L>R) return; if(L <= l && r <= R) { add[rt] += w; mx[rt] += w; return; } PushDown(rt, r-l+1); int m = (l+r) >> 1; if(L <= m) update(L, R, w, lson); if(m < R) update(L, R, w, rson); PushUp(rt);}int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return mx[rt]; PushDown(rt, r-l+1); int m = (l+r) >> 1; int ret = 0; if(L <= m) ret = max(ret, query(L, R, lson)); if(m < R) ret = max(ret, query(L, R, rson)); return ret;}int main(){ scanf("%d %d", &n, &k); for(int i=1;i<=n;i++) { scanf("%d", &a[i]); if(vis[ a[i] ]) dp[i][1] = dp[i-1][1]; else dp[i][1] = dp[i-1][1]+1; pre[i] = max(vis[ a[i] ], 1); vis[ a[i] ] = i; } for(int ik=2;ik<=k;ik++) { build(1, n, 1, ik-1); dp[1][k] = 1; for(int i=2;i<=n;i++) { update(pre[i], i-1, 1, 1, n, 1); dp[i][ik] = max(dp[i][ik], query(1, i-1, 1, n, 1)); } } printf("%d\n", dp[n][k]);}
阅读全文
0 0
- Codeforces Round #426 (Div. 1) B. The Bakery (DP + 线段树)
- Codeforces Round #426 (Div. 1) B. The Bakery(dp+线段树)
- Codeforces Round #426 (Div. 2) The Bakery 线段树+dp
- Codeforces Round #426 (Div. 2) D. The Bakery(DP+线段树) 好题
- Codeforces Round #426 (Div. 2) D. The Bakery(DP+线段树)
- Codeforces Round #426 (Div. 2)-The Bakery(线段树+DP)
- Codeforces Round #426 (Div. 2) D. The Bakery(DP+线段树)
- Codeforces Round #426 (Div. 2) D. The Bakery(DP+线段树维护)
- Codeforces 833B (Codeforces Round #426) The Bakery DP+线段树
- Codeforces Round #426 (Div. 2) D. The Bakery DP,线段树
- CodeForces 833B Round#426 Div1B&Div2D The Bakery: DP+线段树
- Codeforces Round #426 (Div. 1):B. The Bakery
- CodeForces 833 B.The Bakery(dp+线段树)
- CodeForces 833B The Bakery(dp+线段树优化)
- codeforces 833B. The Bakery(dp+线段树)
- Codeforces-834D The Bakery(线段树+dp)
- Codeforces Round #426 (Div. 2) C. The Meaningless Game 思维 D. The Bakery dp
- Codeforces Round #368 (Div. 2)(B. Bakery 贪心)
- eclipse 快捷键
- ADO.NET
- ProgressBar及其子类系列学习
- 《Ios Human Interface Guidelines》--File Handing
- zoj3435 Ideal Puzzle Bobble 莫比乌斯反演
- Codeforces Round #426 (Div. 1) B. The Bakery (DP + 线段树)
- Ext.FormPanel
- LNMP安装了哪些软件?安装目录在哪?
- springboot异常处理
- 动态代理
- 使用 TexturePacker 进行资源加密
- Java分支与循环
- Java中Map常用方法总结以及遍历方式的汇总
- The Festive Evening