【BZOJ 5125】小Q的书架
Problem
Description
小 \(Q\) 有 \(n\) 本书,每本书有一个独一无二的编号,现在它们正零乱地在地上排成了一排。
小 \(Q\) 希望把这一排书分成恰好 \(k\) 段,使得每段至少有一本书,然后把每段按照现在的顺序依次放到 \(k\) 层书架的每一层上去。
将所有书都放到书架上后,小 \(Q\) 这才突然意识到它们是乱序的,他只好把每一层的书分别按照编号从小到大排序。排序每次可以在 \(1\) 单位时间内交换同一层上两本相邻的书。
请写一个程序,帮助小 \(Q\) 计算如何划分这 \(k\) 段,且如何交换这些书,使得总交换次数最少。
Input Format
第一行包含两个正整数 \(n,k\)。
第二行包含 \(n\) 个互不相同的正整数 \(a_1, a_2, ..., a_n\),分别表示地面上每本书的编号。
Output Format
输出一行一个整数,即最少的总交换次数。
Sample
Input
6 3
4 3 6 2 5 1
Output
1
Explanation
Explanation for Input
按 \([4, 3, 6][2, 5][1]\) 划分,需要排序 \(1 + 0 + 0 = 1\) 次。
Range
\(1 \le n \le 40000, 1 \le k \le min(10, n), \forall 1 \le a_i \le n\)
Algorithm
\(DP\) ,决策单调性
Mentality
其实决策单调性也没啥可怕的地方,主要重点在于你的思考!
我们先列出最朴素的 \(dp\) 方程:\(dp[i][j]\) 表示将前 \(i\) 本书划分到 \(j\) 层书架的最小代价,那么我们设 \(w(i,j)\) 代表区间 \([i,j]\) 内的逆序对数目,我们就有如下方程:
\]
答案即为 \(dp[n][k]\) 。
这样 \(dp\) 的复杂度为 \(n^2k\) , 时间显然过不去。
那么由于式子非常决策单调性,那么我们考虑打表证明,果然有 \(w\) 函数满足四边形不等式。
随后当我们枚举一个 \(j\) 时,我们设 \(g[i]\) 为 \(dp[i][j]\) 的最优决策点,即 \(dp[i][j]=dp[g[i]][j-1]+w(g[i]+1,i)\),则有 \(g[i-1]\le g[i]\) 。
这个证明很简单,对于两个决策点 \(p<q\) ,如果 \(dp[q]+w\le dp[p]+w\) ,由于 \(w\) 函数越来越大,所以如果 \(q\) 比 \(p\) 更优,那么 \(q\) 永远比 \(p\) 更优。所以我们的最优决策点必定单调右移,即 \(g[i-1]\le g[i]\) 。
那么根据这个单调性搞事情,我们考虑分治 \(dp\) ,对于区间 \([l,r]\) 的 \(dp\) ,我们考虑确定它的最优决策点所在的区间 \([L,R]\) 。那么我们找出 \(mid\) 处的最优决策点 \(p\),根据决策单调性,则区间 \([mid+1,r]\) 的最优决策区间必定为 \([p,R]\) ,而区间 \([l,mid-1]\) 的最优决策区间则必定为 \([L,p]\) 。
根据这样递归分治,每次枚举最优决策区间更新 \(mid\) ,并递归处理,枚举决策区间便构成了一颗类似线段树的情况,那么对于同一递归层数,决策区间的和正好就是 \(O(n)\) ,那么决策区间枚举的总复杂度就是 \(nlog\) ,均摊下来,则我们枚举决策点的复杂度变为 \(log\) ,枚举状态复杂度为 \(O(nk)\) 。
样例的递归分治,当 \(k=2\) 时如下图:

由此可见,每层的决策点枚举只会是 \(O(n)\) ,那么总复杂度为 层数× \(n\) ,即 \(O(nlog)\) 。
接下来还剩一个状态转移,那么我们只需要管 \(w\) 函数如何快速地求出来就好了。这里我们先看我们的处理顺序为先递归左区间再递归右区间,那么大多数时候 \(w\) 的右端点只是根据 \(dp\) 需求不断增加 \(1\) ,递归下去的时候也只是减少一些。
则我们可以考虑维护一个类似莫队的东西,维护一个全局的 \(L\) 与 \(R\) ,每次需要获取答案的时候,我们就将 \(L\) 和 \(R\) 一步一步移动到指定位置,用树状数组动态维护逆序对即可。这样做的话大概总复杂度是 \(nlog\) 带个玄学常数?那么均摊下来就是 \(log\) 的复杂度。
则最后的时间复杂度=枚举状态×枚举决策点×状态转移=\(O(nk)×O(log)×O(log)\)=\(O(nklog^2)\) 。能够通过题目。
Code
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, K, sum, L, R, now, a[40001], c[40001], f[40001][11];
void add(int k, int x) {
for (int i = k; i <= n; i += i & -i) c[i] += x;
}
int query(int x) {
int ans = 0;
for (int i = x; i > 0; i -= i & -i) ans += c[i];
return ans;
}
void Move(int l, int r) //莫队式移动
{
while (L < l) sum -= query(a[L] - 1), add(a[L++], -1);
while (L > l) sum += query(a[L - 1] - 1), add(a[--L], 1);
while (R < r) sum += R - L + 1 - query(a[R + 1]), add(a[++R], 1);
while (R > r) sum -= R - L + 1 - query(a[R]), add(a[R--], -1);
}
void solve(int l, int r, int L, int R) {
if (l > r) return;
int mid = (l + r) >> 1, p = L;
for (int i = L; i <= min(mid - 1, R); i++) {
Move(i + 1, mid);
int Sum = f[i][now - 1] + sum;
if (Sum < f[mid][now]) f[mid][now] = Sum, p = i; //确定最优决策点
}
solve(l, mid - 1, L, p);
solve(mid + 1, r, p, R); //递归
}
int main() {
cin >> n >> K;
L = 1; //初始化莫队指针
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
memset(f, 10, sizeof(f));
for (int i = 1; i <= n; i++) Move(1, i), f[i][1] = sum; //先计算 k=1
for (now = 2; now <= K; now++) solve(1, n, 1, n); //开始递归
cout << f[n][K];
}
【BZOJ 5125】小Q的书架的更多相关文章
- BZOJ5125: [Lydsy1712月赛]小Q的书架【决策单调性优化DP】【BIT】【莫队】【分治】
小Q有n本书,每本书有一个独一无二的编号,现在它们正零乱地在地上排成了一排. 小Q希望把这一排书分成恰好k段,使得每段至少有一本书,然后把每段按照现在的顺序依次放到k层书架的每一层上去.将所有书都放到 ...
- bzoj 4017: 小Q的无敌异或
4017: 小Q的无敌异或 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 593 Solved: 197[Submit][Status][Discu ...
- bzoj 5125: [Lydsy1712月赛]小Q的书架
新学了一波 决策单调性 dp 套路.... 这种dp一般是长这样的 => f[i][j] = max/min { f[i-1][k] + cost(k+1,j)} ,其中cost函数满足四边形 ...
- BZOJ5125 小Q的书架(决策单调性+动态规划+分治+树状数组)
设f[i][j]为前i个划成j段的最小代价,枚举上个划分点转移.容易想到这个dp有决策单调性,感性证明一下比较显然.如果用单调栈维护决策就不太能快速的求出逆序对个数了,改为使用分治,移动端点时树状数组 ...
- [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
显然有决策单调性,但由于逆序对不容易计算,考虑分治DP. solve(k,x,y,l,r)表示当前需要选k段,待更新的位置为[l,r],这些位置的可能决策点区间为[x,y].暴力计算出(l+r)/2的 ...
- BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)
题意:N个数,按顺序划分为K组,使得逆序对之和最小. 思路:之前能用四边形不等式写的,一般网上都还有DP单调性分治的做法,今天也尝试用后者写(抄)了一遍.即: 分成K组,我们进行K-1次分治,get( ...
- bzoj 4815 小Q的表格 —— 反演+分块
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4815 思路就和这里一样:https://blog.csdn.net/leolyun/arti ...
- BZOJ 4017 小 Q 的无敌异或 ( 树状数组、区间异或和、区间异或和之和、按位计贡献思想 )
题目链接 题意 : 中文题 分析 : 首先引入两篇写的很好的题解 题解一.题解二 听说这种和异或相关区间求和的问题都尽量按位考虑 首先第一问.按二进制位计贡献的话.那么对于第 k 位而言 其贡献 = ...
- BZOJ [Cqoi2017] 小Q的棋盘
题解:枚举最后在哪里停止,然后剩下的步数/2 也就是找最大深度 枚举终止位置算是一种思路吧 #include<iostream> #include<cstdio> #inclu ...
随机推荐
- 张春晖让视频的每词每句都可搜索:Autotiming 可以自动配字幕,还将改变哪些领域?
张春晖让视频的每词每句都可搜索:Autotiming 可以自动配字幕,还将改变哪些领域? 对于一些电视观众来说,寻找电视节目字幕中“有趣”的Bug,拍照发到网上与其他人共同嘲笑一下,是一种观看节目之外 ...
- JSVC技术
如果我们的某个项目时web项目,我们很容易就可以放置在Tomcat中进行启动. 可是如果我们的项目不是web项目,我们又需要在单独启动时,我们又应该怎么办呢? 引出了我们今天的主人公:JSVC ...
- java-web的mybatis的学习
idea开发必须是把Mapper文件与配置文件放到Resources标记的classpath目录下,eclips好像放到哪都行指定好路径就可以了, maven里面做好配置resources的路径,不然 ...
- css 初级进阶
摘自:https://www.jianshu.com/p/dcc40ccc9841 CSS中级 Class和ID选择器 CSS初级教程中我们可以使用HTML标签选择器定义样式. 同样你也可以使用Cla ...
- C++ STL--顺序容器(vector)
STL(标准模板库) 一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量.链表.队列.栈. C++标准模板库的核心包含以下组件: ...
- javaweb笔记—01(编程英语、常识、Tomcat配置问题)
第一部分: 编程英语: legal:adj. 法律的:合法的:法定的 Userful :出版商 sponsor: n. 赞助者:主办者:保证人 | vt. 赞助:发起 essential:n. 本质 ...
- 小纪a
感觉挺好的两段代码:虽然已经存在,但是这是我自己敲出来的,没有照抄,真心话,所以记录下来. 1.菱形代码: #include <stdio.h>void main() { int i, j ...
- Golang切片的三种简单使用方式及区别
概念 切片(slice)是建立在数组之上的更方便,更灵活,更强大的数据结构.切片并不存储任何元素而只是对现有数组的引用. 三种方式及细节案例 ①定义一个切片,然后让切片去引用一个已经创建好的数组 pa ...
- linux 文件 md5校验
为解决官方发布的软件包被别人更改或者软件在传输过程中出现传输错误等问题,软件官方在提供软件包的同时,还提供一个保存MD5校验码的文件. Linux/unix中可以使用命令 # md5sum 文件名 方 ...
- 06: 字典、顺序表、列表、hash树 实现原理
算法其他篇 目录: 1.1 python中字典对象实现原理 1.2 顺序表 1.3 python 列表(list) 1.1 python中字典对象实现原理返回顶部 注:字典类型是Python中最常 ...