有 \(n\) 个数构成的序列 \({a_i}\),要将它划分为 \(k\) 段,定义每一段的权值为这段中 \((i,j) \ s.t. \ i<j,\ a_i=a_j\) 的个数,求一种划分方案,使得各段的权值和最小。 \(n \leq 10^5, k \leq min(n,20), a_i \leq n\)

设 \(f[i][j]\) 表示将 \(a_{1..j}\) 分为 \(i\) 段的最小价值,则很容易得到转移方程

\[f[i][j]=\min (f[i-1][k]+cost(k+1,j)) \ \ \ (k<j)
\]

暴力转移是 \(O(n^2 k)\),但这里有决策单调性,即 \(p_j\) 为 \(f[i][j]\) 的最优转移点(如果有多个就取最左边的),那么对于任意 \(k<j\) 一定有 \(p_k \leq p_j\)

注:形如 \(f_i = min/max_{j=1}^{i-1} g_j + w_{i,j}\),记 \(f_i\) 的最优决策点为 \(p_i\),即 \(f_i\) 从 \(g_{p_i} + w_{i,p_i}\) 处转移最优,如果满足 \(p_i \leq p_{i+1}\),则称该方程满足决策单调性

(不想证明可以先写个暴力打表然后一眼看规律)

所以我们整体二分来加速转移

考虑我们当前求解一段区间 \([l,r]\),所有 \(f_{i,j},\ j \in [l,r]\) 的最优决策点在 \([L,R]\) 之间。

对于 \([l,r]\) 的中点 \(mid\),可以暴力扫一遍 \([L,R]\),找到最优决策点 \(k\)

那么由于决策单调,所有 \(f_{i,j},\ j \in [l,mid]\) 的决策则落在 \([L,k]\) 上,所有 \(f_{i,j},\ j \in [mid+1,r]\) 的决策则落在 \([k,R]\) 上

总体时间复杂度 \(O(kn \log n)\)

因为某个循环边界写宽了然后就TLE了

#include <bits/stdc++.h>
using namespace std; #define int long long
const int N = 1000005;
int n,m,f[N],g[N],a[N],buc[N]={1,0},cnt;
signed pl,pr; inline void push(signed x) {
cnt+=buc[x];
buc[x]++;
} inline void pop(signed x) {
buc[x]--;
cnt-=buc[x];
} void trans(signed l,signed r) {
while(l<pl) pl--, push(a[pl]);
while(r>pr) pr++, push(a[pr]);
while(l>pl) pop(a[pl]), pl++;
while(r<pr) pop(a[pr]), pr--;
//cout<<l<<" "<<r<<" "<<cnt<<endl;
} void solve(int l,int r,int L,int R) {
int mid=(l+r)/2;
int mx=1e18,k=0;
for(int i=L;i<=min(R,mid-1);i++) { //!
trans(i+1,mid);
if(g[i]+cnt<mx) {
mx=g[i]+cnt;
k=i;
}
}
f[mid]=mx;
if(l<r) {
solve(l,(l+r)/2-1,L,k); //!
solve((l+r)/2+1,r,k,R);
}
} signed main() {
ios::sync_with_stdio(false);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++) {
trans(1,i);
f[i]=g[i]=cnt;
//<<g[i]<<" ";
}//cout<<endl;
for(int i=2;i<=m;i++) {
solve(1,n,1,n);
for(int j=1;j<=n;j++) g[j]=f[j];
/*for(int j=1;j<=n;j++) {
cout<<f[j]<<" ";
}
cout<<endl;*/
}
cout<<f[n];
}

最新文章

  1. BZOJ1527 : [POI2005]Pun-point
  2. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
  3. RecyclerView的使用(四)
  4. shell学习之路:重定向符号的使用
  5. 记录一款不错的插件fullpage.js
  6. iproute-2.6.32
  7. MySQL基础之第13章 MySQL函数
  8. php多条件组合查询
  9. JS实现用键盘控制DIV上下左右+放大缩小与变色
  10. php面向对象(一)---2017-04-17
  11. HTML基础教程-段落
  12. MySQL 行锁 表锁机制
  13. Java锁Synchronized对象锁和类锁区别
  14. python环境搭建-requests的简单安装(适合新手)
  15. conda和pip相关操作
  16. 2018/12.21:函数this的指向
  17. Unicode编码问题 如:\u529e\u7406\u9996\u6c7d\u52a0\u6cb9
  18. beego+vue父子组件通信(父子页面传值、父子组件传值、父子路由传值)
  19. kubectl客户端工具远程连接k8s集群
  20. 关于事件循环机制event loop

热门文章

  1. NR / 5G - Uplink Carrier Waveform Generation
  2. JDK14都要问世了,你还在用JDK8吗
  3. 寒假答辩作品:Java小游戏
  4. Lambda如何实现条件去重distinct List,如何实现条件分组groupBy List
  5. while 循环 实例
  6. GNU make doc - 3.8
  7. python基础入门之四 —— 列表
  8. java设计模式学习笔记--开闭原则
  9. Invalid `Podfile` file: undefined method `pod&#39; for main:Object.
  10. mysql在建表语句中添加索引