题目链接 The Bakery

题目大意:目标是把$n$个数分成$k$组,每个组的值为这个组内不同的数的个数,求$k$个组的值的和的最大值。

题目分析:

这道题我的解法可能和大众解法不太一样……我用主席树求$ask(l, r)$——$l$到$r$之间有多少个不同的数。

然后就是$DP$了。

这道题的数据规模是

$n <= 35000$, $k <= 50$

首先直接$DP$的做法还是比较简单的。代码如下。

其中$f[i][j]$为前$i$个数分成$j$组可以得到的最大的和

        rep(i, 1, n){
    tmp.set(a[i]);
    f[i][1] = tmp.count();
  }   rep(j, 2, k){
  rep(i, j, n){
  rep(k, 0, i - 1){
f[i][j] = max(f[i][j], f[k][j - 1] + ask(k + 1, i));
}
}
}

我们发现这样的时间复杂度是$O(n^{2}klogn)$的,效率不够高。

怎么优化呢?

这道题有一个结论:

假设$f[i][j]$的最优方案是从$f[x][j - 1]$得到的,$f[i +1][j]$的最优方案是从$f[y][j - 1]$得到的。

那么一定有 $x <= y$

(证明是某个外国小哥给出的)

我们可以用分治进行优化(也就是整体二分吧)

求$f[i][k]$  $(l <= i <= r)$的时候,我们先求$f[mid][k]$

其中$mid = (l + r) / 2$

求$f[mid][k]$的时候,我们对于$f[j][k - 1]$,$j$从$1$枚举到$mid$

这个时候我们要记录一个$x$,即$f[mid][k]$的最优方案是从$f[x][k - 1]$得到的。

那么我们就可以两边继续递归下去,分别求两个四等分点位置

$f[p1][k]$  $(l <= i <= mid - 1)$  (此时对于$f[j][k - 1]$,$j$从$1$枚举到$x$)

$f[p2][k]$  $(mid + 1 <= i <= r)$(此时对于$f[j][k - 1]$,$j$从$x$枚举到$n$)

以此类推

于是上述代码中的时间复杂度中的一个$n$变成了$logn$

时间复杂度 $O(nlog^{2}(n)k)$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 35010;
const int M = 4e6 + 10; int n, tot, q, a[N];
int T[M], lson[M], rson[M], val[M];
int nxt[N], b[N];
int k;
int f[N][53]; bitset <N> tmp; int build(int l, int r){
int rt = tot++;
val[rt] = 0;
int m = (l + r) >> 1;
if(l != r){
lson[rt] = build(l, m);
rson[rt] = build(m + 1, r);
}
return rt;
}
int update(int rt, int pos, int v){
int newrt = tot++, tmp = newrt;
int l = 1, r = n;
val[newrt] = val[rt] + v;
while(l < r)
{
int m = (l + r) >> 1;
if(pos <= m)
{
lson[newrt] = tot++;
rson[newrt] = rson[rt];
newrt = lson[newrt];
rt = lson[rt];
r = m;
}
else
{
rson[newrt] = tot++;
lson[newrt] = lson[rt];
newrt = rson[newrt];
rt = rson[rt];
l = m + 1;
}
val[newrt] = val[rt] + v;
}
return tmp;
} int query(int rt, int pos){
int ret = 0;
int l = 1, r = n;
while(pos > l){
int m = (l + r) >> 1;
if(pos <= m){
ret += val[rson[rt]];
rt = lson[rt];
r = m;
}
else{
l = m + 1;
rt = rson[rt];
}
}
return ret + val[rt];
} int ask(int l, int r){ return query(T[r], l); } void init(){
tot = 0;
memset(nxt, -1, sizeof(nxt));
rep(i, 1, n) b[i - 1] = a[i];
sort(b, b + n);
int cnt = unique(b, b + n) - b;
T[0] = build(1, n);
rep(i, 1, n){
int id = lower_bound(b, b + cnt, a[i]) - b;
if(nxt[id] == -1)
T[i] = update(T[i - 1], i, 1);
else{
int t = update(T[i - 1], nxt[id], -1);
T[i] = update(t, i, 1);
}
nxt[id] = i;
}
} void solve(int j, int l, int r, int st, int ed){
if (l > r) return;
int mid = (l + r) >> 1;
int x; rep(i, st, min(mid, ed)){
if (f[i - 1][j - 1] + ask(i, mid) >= f[mid][j]){
f[mid][j] = f[i - 1][j - 1] + ask(i, mid);
x = i;
}
} if (l != r){
solve(j, l, mid - 1, st, x);
solve(j, mid + 1, r, x, ed);
}
} int main(){ scanf("%d%d", &n, &k);
rep(i, 1, n) scanf("%d", a + i); init();
rep(i, 1, n){
tmp.set(a[i]);
f[i][1] = tmp.count();
}
/*
rep(j, 2, k){
rep(i, j, n){
rep(k, 0, i - 1){
f[i][j] = max(f[i][j], f[k][j - 1] + ask(k + 1, i));
}
}
}
*/ rep(j, 2, k) solve(j, 1, n, 1, n); printf("%d\n", f[n][k]);
return 0; }

Codeforces 833B The Bakery(主席树 + 决策单调性优化DP)的更多相关文章

  1. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  2. CF868F Yet Another Minimization Problem 分治决策单调性优化DP

    题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...

  3. 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)

    传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...

  4. [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)

    第一种方法是决策单调性优化DP. 决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优. 根号函数是一个典型的具有决策单调性的函数,由 ...

  5. BZOJ2216 Poi2011 Lightning Conductor 【决策单调性优化DP】

    Description 已知一个长度为n的序列a1,a2,...,an. 对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt( ...

  6. 决策单调性优化dp 专题练习

    决策单调性优化dp 专题练习 优化方法总结 一.斜率优化 对于形如 \(dp[i]=dp[j]+(i-j)*(i-j)\)类型的转移方程,维护一个上凸包或者下凸包,找到切点快速求解 技法: 1.单调队 ...

  7. 洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)

    题面传送门 首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times ...

  8. BZOJ4899: 记忆的轮廓【概率期望DP】【决策单调性优化DP】

    Description 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增, 在[1,n]中,一共有n个节点.我 ...

  9. 算法学习——决策单调性优化DP

    update in 2019.1.21 优化了一下文中年代久远的代码 的格式…… 什么是决策单调性? 在满足决策单调性的情况下,通常决策点会形如1111112222224444445555588888 ...

随机推荐

  1. DirectX9(翻译):介绍

    一.简介 二.DirectX Software Development Kit 这本帮助文档总共分为五大部分:DirectX Software Development Kit DirectX Grap ...

  2. OpenCV2:第八章 界面事件

    一.简介 OpenCV中提供了程序界面中的鼠标和键盘事件 二.鼠标事件 //  设置鼠标回调函数 void setMouseCallback ( const string& winname, ...

  3. 玩4K必备知识:HDMI1.4、2.0、2.0a、2.0b接口参数对比【扫盲贴】

    https://www.4k123.com/thread-55369-1-1.html 前言:玩4K的同学都知道,HDMI接口是视频传输最常用的接口,但是这个接口却有好几个版本HDMI1.4.HDMI ...

  4. C# Excel常用控件总结

    参考:https://blog.csdn.net/waterstar50/article/details/80590355 1.ClosedXML2.EPPlus 教程:http://www.cnbl ...

  5. mac拷贝原版和权限修复的命令行工具

    建议直接从安装盘中用命令复制,因为上传的kext权限会变,导致签名失败. 假定安装盘盘符是install_osx: sudo cp -R /Volumes/install_osx/S*/L*/E*/A ...

  6. WebAssembly MDN简单使用

    MDN 就是通过编译器编译完成c后生成的胶水代码 引入js 就能直接调用定义在c或者c++中的函数了 c代码如下: #include <stdio.h> #include <stdl ...

  7. [JOY]1143 飘飘乎居士的约会

    题目描述 又是美妙的一天,这天飘飘乎居士要和MM约会,因此他打扮的格外帅气.但是,因为打扮的时间花了太久,离约会的时间已经所剩无几. 幸运的是,现在飘飘乎居士得到了一张nm的地图,图中左上角是飘飘乎居 ...

  8. 【REDIS】 redis-cli 命令

    Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用. 在编程时,比如使用Redis 的Java语言包,这些命令都有对应的方法.下面将 ...

  9. 什么是php?php的优缺点有哪些?与其它编程语言的优缺点?

    身为一个PHP开发者,有必要了解一下PHP的缺点,知道每种语言的优点和缺点,才能知道某种语言在什么场景下适合使用,在什么场景下不适合使用. 这个问题我曾经面试的时候遇到过,我之前没总结过,第一问大部分 ...

  10. leetcode-1-basic

    leetcode-algorithm 1. Two Sum 解法:循环,试呗..简单粗暴.. class Solution { public: vector<int> twoSum(vec ...