题意

给定一个序列 \(\{a_1, a_2, \cdots, a_n\}\),要把它分成恰好 \(k\) 个连续子序列。

每个连续子序列的费用是其中相同元素的对数,求所有划分中的费用之和的最小值。

\(2 \le n \le 10^5, 2 \le k \le \min(n, 20), 1 \le a_i \le n\)

题解

\(k\) 比较小,可以先考虑一个暴力 \(dp\) 。

令 \(dp_{k, i}\) 为前 \(i\) 个数划分成 \(k\) 段所需要的最小花费。

那么转移如下

\[dp_{k, i} = \min_{j \le i} dp_{k - 1, j - 1} + w_{j, i}
\]

其中 \(w_{j, i}\) 为 \(j \sim i\) 这段划分出来需要的花费,也就是 \([j, i]\) 区间内相同元素对数。

暴力做是 \(O(n^2 k)\) 的,无法通过。

说到最优区间划分,我就想起了决策单调性,今年下半年

至于为什么满足决策单调?考虑证明 \(\mathrm{1D/1D}\) 上的 四边形不等式。具体证明可以参考此处

我们现在只有一个问题了, 就是如何快速求出 \(w_{j, i}\) 。

可以考虑把序列分块,然后预处理块到块的答案以及点到一个块的答案,然后再算算边角。

然后这个配合 二分+单调栈 可以做到 \(O(nk \sqrt n \log n)\) ,还是过不去。

对于这种分层 \(dp\) 来说,分治的复杂度就可以正确,因为每次不需要先分治左区间再算右区间,可以扫完整个区间得到 \(mid\) 的最优决策点,然后就可以把 \([l, mid)\) 和 \((mid, r]\) 的决策点分开了。

这样单次求解的话,每层是 \(O(n)\) 的,那么复杂度是 \(O(n \log n)\) 的。

然后此时我们就可以很好的算 \(w_{j, i}\) 了,要怎么算呢?

可以暴力一点做,考虑类似莫队那样维护当前计算区间的 \([l, r]\) ,然后看接下来要算的 \([l', r']\) 的相对位置,就可以得到相应的区间的花费了。

复杂度?其实是对的。具体原因可以参考非指针移动的那种做法,每次只会移动当前区间长度的指针。

这个其实是一样的,因为每次需要利用的相邻两个区间是一样的,这种移动方法的复杂度是平面上两点的曼哈顿距离,显然不会更劣。

那么最后复杂度就是 \(O(nk \log n)\) 的,似乎我的写法跑的挺快?

代码

很好写啊qwq

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
} const int N = 2e5 + 1e3; int n, k, a[N], times[N]; int l, r; ll res, dp[25][N]; void Move(int L, int R) {
while (l > L) res += times[a[-- l]] ++;
while (l < L) res -= -- times[a[l ++]];
while (r > R) res -= -- times[a[r --]];
while (r < R) res += times[a[++ r]] ++;
} void Divide(int k, int l, int r, int dl, int dr) {
if (l > r) return;
int mid = (l + r) >> 1, dmid = dl;
dp[k][mid] = 0x3f3f3f3f3f3f3f3f;
For (i, dl, min(mid, dr)) {
Move(i, mid);
if (chkmin(dp[k][mid], dp[k - 1][i - 1] + res)) dmid = i;
}
Divide(k, l, mid - 1, dl, dmid);
Divide(k, mid + 1, r, dmid, dr);
} int main () { File(); n = read(); k = read(); For (i, 1, n) a[i] = read(); For (i, 1, n)
dp[1][i] = (res += times[a[i]] ++);
res = 0; Set(times, 0); l = 1; r = 0;
For (i, 2, k) Divide(i, 1, n, 1, n);
printf ("%lld\n", dp[k][n]); return 0; }

CodeForces 868F Yet Another Minimization Problem(决策单调性优化 + 分治)的更多相关文章

  1. Codeforces 868F Yet Another Minimization Problem 决策单调性 (看题解)

    Yet Another Minimization Problem dp方程我们很容易能得出, f[ i ] = min(g[ j ] + w( j + 1, i )). 然后感觉就根本不能优化. 然后 ...

  2. CF868 F. Yet Another Minimization Problem 决策单调优化 分治

    目录 题目链接 题解 代码 题目链接 CF868F. Yet Another Minimization Problem 题解 \(f_{i,j}=\min\limits_{k=1}^{i}\{f_{k ...

  3. Codeforces 868F. Yet Another Minimization Problem

    Description 给出一个长度为 \(n\) 的序列,你需要将它分为 \(k\) 段,使得每一段的价值和最小,每一段的价值是这一段内相同的数的个数 题面 Solution 容易想到设 \(f[i ...

  4. Codeforces 868F. Yet Another Minimization Problem【决策单调性优化DP】【分治】【莫队】

    LINK 题目大意 给你一个序列分成k段 每一段的代价是满足\((a_i=a_j)\)的无序数对\((i,j)\)的个数 求最小的代价 思路 首先有一个暴力dp的思路是\(dp_{i,k}=min(d ...

  5. Codeforces 868F Yet Another Minimization Problem(分治+莫队优化DP)

    题目链接  Yet Another Minimization Problem 题意  给定一个序列,现在要把这个序列分成k个连续的连续子序列.求每个连续子序列价值和的最小值. 设$f[i][j]$为前 ...

  6. cf868F. Yet Another Minimization Problem(决策单调性 分治dp)

    题意 题目链接 给定一个长度为\(n\)的序列.你需要将它分为\(m\)段,每一段的代价为这一段内相同的数的对数,最小化代价总和. \(n<=10^5,m<=20\) Sol 看完题解之后 ...

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

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

  8. 洛谷CF868F Yet Another Minimization Problem(动态规划,决策单调性,分治)

    洛谷题目传送门 貌似做所有的DP题都要先搞出暴力式子,再往正解上靠... 设\(f_{i,j}\)为前\(i\)个数分\(j\)段的最小花费,\(w_{l,r}\)为\([l,r]\)全在一段的费用. ...

  9. [bzoj1563][NOI2009]诗人小G(决策单调性优化)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1563 分析: 首先可得朴素的方程:f[i]=min{f[j]+|s[j]-j-s[i] ...

随机推荐

  1. 腾讯云centos7远程连接配置

    1.申请腾讯云 注册腾讯云账号,申请一个centos7的服务器,1G内存,1核处理器,1M网速. 对于这种入门级配置,建议还是别用windows server了,不然不装任何东西,光运行系统就需要60 ...

  2. iOS---------- Safe Area Layout Guide before iOS 9.0

    如果你们的项目不做iOS9以下支持就打开main.storyboard    去除Use safe Area Layout 如果不考虑iOS9以下支持就按照下面的步骤 选中控制器,右边面板的Build ...

  3. WebView断网提示

    转载请标明出处,维权必究:https://www.cnblogs.com/tangZH/p/9913968.html 重写WebViewClient中的方法,然后WebView.setWebViewC ...

  4. 章节九、1-Selenium环境配置

    一.Selenium环境安装配置,这里使用Selenium WebDriver 3.6.0 1.下载Selenium WebDriver (点击后网站响应比较慢,需要多等等) 2.打开该网址后点击“d ...

  5. DAS、SAN和NAS三种存储方式

    DAS存储 DAS存储在我们生活中是非常常见的,尤其是在中小企业应用中,DAS是最主要的应用模式,存储系统被直连到应用的服务器中,在中小企业中,许多的数据应用是必须安装在直连的DAS存储器上. DAS ...

  6. MySQL 修改账号的IP限制条件

    今天遇到一个需求:修改MySQL用户的权限,需要限制特定IP地址才能访问,第一次遇到这类需求,结果在测试过程,使用更新系统权限报发现出现了一些问题, 具体演示如下. 下面测试环境为MySQL 5.6. ...

  7. Tomcat开启SSL协议支持

    一.生成keyStore 要使用ssl connector,必须先创建一个keystore.他包含了服务器中被客户端用于验证服务器的数字证书.一旦客户端接受了这个证书,客户端就可以使用public k ...

  8. linux内核IDR机制详解【转】

    这几天在看Linux内核的IPC命名空间时候看到关于IDR的一些管理性质的东西,刚开始看有些迷茫,深入看下去豁然开朗的感觉,把一些心得输出共勉. 我们来看一下什么是IDR?IDR的作用是什么呢? 先来 ...

  9. 2星|《IT真相》:日本咨询师面对美国云服务的发展,对日本IT业哀其不争

    IT真相-打通IT与商务的通路 I 作者是日本管理咨询师,对日本的IT和金融业了解比较多.书的内容是:作者看到美国的云服务发展壮大,日本IT业没能抓住机会,对日本IT业做了一些批评,比如不思进取,不了 ...

  10. Java开发学习心得(一):SSM环境搭建

    目录 Java开发学习心得(一):SSM环境搭建 1 SSM框架 1.1 Spring Framework 1.2 Spring MVC Java开发学习心得(一):SSM环境搭建 有一点.NET的开 ...