小Q有n本书,每本书有一个独一无二的编号,现在它们正零乱地在地上排成了一排。

小Q希望把这一排书分成恰好k段,使得每段至少有一本书,然后把每段按照现在的顺序依次放到k层书架的每一层上去。将所有书都放到书架上后,小Q这才突然意识到它们是乱序的,他只好把每一层的书分别按照编号

从小到大排序。排序每次可以在1单位时间内交换同一层上两本相邻的书。

请写一个程序,帮助小Q计算如何划分这k段,且如何交换这些书,使得总交换次数最少。

Input

第一行包含两个正整数n; k(1≤n≤40000;1≤k≤min(10; n))。

第二行包含n个互不相同的正整数a1,a2,..., an(1≤ai≤n),分别表示地面上每本书的编号。

Output

输出一行一个整数,即最少的总交换次数。

Examples

stdin

6 3

4 3 6 2 5 1

stdout

1

Notes

按\([4,3,6][2,5][1]\)划分,需要排序1 + 0 + 0 = 1次。


思路

分成k段,最小化逆序对个数之和

非常套路了吧

决策单调性非常显然

那么就对于每一层进行分治

然后中间怎么维护逆序对个数?

可以用莫队+树状数组

因为首尾删/加数的逆序对个数是很好维护的(bit查一下就可以啦)

然后就很简单了

几分钟就写完了。。编译过了就A了


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
typedef pair<int, int> pi;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e6 + 10;
int n, m, a[N];
int nowl = 1, nowr = 0;
ll res = 0, dp[N][12];
int bit[N]; void add(int x) {
for (; x <= n; x += x & (-x)) ++bit[x];
} void sub(int x) {
for (; x <= n; x += x & (-x)) --bit[x];
} int query(int x) {
int result = 0;
for (; x; x -= x & (-x)) result += bit[x];
return result;
} int query(int l, int r) {
return query(r) - query(l - 1);
} void move_step(int al, int ar) {
while (nowr < ar) {
++nowr;
res += query(a[nowr], n);
add(a[nowr]);
}
while (nowl > al) {
--nowl;
res += query(1, a[nowl]);
add(a[nowl]);
}
while (nowr > ar) {
sub(a[nowr]);
res -= query(a[nowr], n);
--nowr;
}
while (nowl < al) {
sub(a[nowl]);
res -= query(1, a[nowl]);
++nowl;
}
}
void solve(int l, int r, int ql, int qr, int k) {
if (l > r) return;
int mid = (l + r) >> 1, pos = mid;
fu(i, ql, min(qr, mid - 1)) {
move_step(i + 1, mid);
if (dp[i][k - 1] + res < dp[mid][k]) {
dp[mid][k] = dp[i][k - 1] + res;
pos = i;
}
}
solve(l, mid - 1, ql, pos, k);
solve(mid + 1, r, pos, qr, k);
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
Read(n), Read(m);
fu(i, 1, n) Read(a[i]);
fu(i, 1, n)
fu(j, 0, m) dp[i][j] = INF_of_ll;
dp[0][0] = 0;
fu(i, 1, m) solve(1, n, 0, n, i);
Write(dp[n][m]);
return 0;
}

BZOJ5125: [Lydsy1712月赛]小Q的书架【决策单调性优化DP】【BIT】【莫队】【分治】的更多相关文章

  1. BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)

    题意:N个数,按顺序划分为K组,使得逆序对之和最小. 思路:之前能用四边形不等式写的,一般网上都还有DP单调性分治的做法,今天也尝试用后者写(抄)了一遍.即: 分成K组,我们进行K-1次分治,get( ...

  2. [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)

    显然有决策单调性,但由于逆序对不容易计算,考虑分治DP. solve(k,x,y,l,r)表示当前需要选k段,待更新的位置为[l,r],这些位置的可能决策点区间为[x,y].暴力计算出(l+r)/2的 ...

  3. bzoj 5125: [Lydsy1712月赛]小Q的书架

    新学了一波 决策单调性 dp 套路.... 这种dp一般是长这样的 => f[i][j] = max/min  { f[i-1][k] + cost(k+1,j)} ,其中cost函数满足四边形 ...

  4. 决策单调性优化dp

    决策单调性: 对于一些dp方程,经过一系列的猜想和证明,可以得出,所有取的最优解的转移点(即决策点)位置是单调递增的. 即:假设f[i]=min(f[j]+b[j]) (j<i) 并且,对于任意 ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 20155239 2016-2017-2 《Java程序设计》第7周学习总结

    教材学习内容总结 1.了解Lambda语言 "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的 ...

  2. python uwsgi报错epoll_ctl(): Bad file descriptor

    今天安装了uwsgi+supervisord+nginx,一直访问不了 直接启动uwsgi使用nginx访问,查看有大量报错:epoll_ctl(): Bad file descriptor [cor ...

  3. Java的Servlet、Filter、Interceptor、Listener

    写在前面: 使用Spring-Boot时,嵌入式Servlet容器可以通过扫描注解(@ServletComponentScan)的方式注册Servlet.Filter和Servlet规范的所有监听器( ...

  4. 常用php操作redis命令整理(一)通用及字符串类型

    Key相关操作 TYPE 类型检测,字符串返回string,列表返回 list,set表返回set/zset,hash表返回hash,key不存在返回0 <?php echo $redis-&g ...

  5. 从官网学习Node.js FS模块方法速查

    最新文档请查看仓库 https://github.com/wangduandu... 1. File System 所有文件操作提供同步和异步的两种方式,本笔记只记录异步的API 异步方式其最后一个参 ...

  6. mybatis的namespace

    Mybatis的namespace是用来绑定Dao接口的,使用了namespace之后就可以不用写接口实现类,dao接口的方法对应mapper.xml中的sql语句. 详情见:https://blog ...

  7. HDU 2457 DNA repair(AC自动机+DP)题解

    题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...

  8. luogu P1141 01迷宫

    https://www.luogu.org/problem/show?pid=1141 还不太会用 BFS 然后就跟着感觉走了一波 经历了很多错误 刚开始的读入 然后BFS的过程 最后T三个点 看到别 ...

  9. Matplotlib 练习题

    1. 绘制一个二维随机漫步的图形 直接上代码: %pylab inline nsteps = 1000 draws = np.random.randint(-1,2,size=(2,nsteps)) ...

  10. Java回顾之网络通信

    在这篇文章里,我们主要讨论如何使用Java实现网络通信,包括TCP通信.UDP通信.多播以及NIO. TCP连接 TCP的基础是Socket,在TCP连接中,我们会使用ServerSocket和Soc ...