Estimation

给出一个长度为n序列\(\{a_i\}\),将其划分成连续的K段,对于其中一段\([l,r]\),设其中位数为m,定义其权值为\(\sum_{i=l}^r|m-a_i|\),求最小的权值之和,\(n\leq 2000,K\leq 25\)。

显然设\(f[i][j]\)表示前i个数划分成j段的的最小权值和,设\(m(i,j)\)为\(i\sim j\)的作为一段的权值,所以有

\[f[i][j]=\min_{0\leq k<i}\{f[k][j-1]+m(k+1,i)\}
\]

边界:\(f[0][0]=0\),其余无限大

答案:\(f[n][K]\)

注意到时间复杂度\(2000^2\times 25=10^8\),为一亿,可以险过,关键在于快速求二元函数m,而求m需要解决的是动态维护一段序列中中间大的数,显然中位数的位置是递增的,可以考虑双堆堆顶优化,不难得知对于序列\(b_1,b_2,...,b_p\)而言设其中位数为\(b_q\),于是有权值为

\[\sum_{i=1}^p|b_i-b_q|=|b_p-b_q|+...+|b_q-b_q|+...+|b_q-b_1|=
\]

\[=b_p-b_q+..+b_q-b_q+...+b_q-b_1=(b_p+...+b_{q+1})-(b_q+...+b_1)+qb_q-(p-q)b_q=
\]

\[\sum_{i=q+1}^pb_i-\sum_{i=1}^qb_i+(2q-p)b_q
\]

于是对于权值,我们只要维护这样一个式子即可,步骤如下

  1. 枚举左端点i,设大根堆为H,小根堆为E
  2. 初始化\(m(i,i)=0,k=-a_i\),H加入\(a_i\)
  3. 枚举右端点j
  4. 如果\(a_j\leq H.top()\),那么\(E.push(H.top()),H.pop(),k+=E.top()\times 2,H.push(a_j),k-=a_j\)
  5. 否则\(E.push(a_j),k+=a_j\)
  6. 如果\(i-j+1\)为偶数的话,那么\(H.push(E.top()),E.pop(),k-=H.top()\times 2\)
  7. 计入答案\(m(i,j)=k+(2q-p)\times H.top()\)

参考代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <functional>
#include <cstring>
#define il inline
#define ri register
#define intmax 0x7fffffff
using namespace std;
int a[2001],m[2001][2001],dp[2001][26];
priority_queue<int,vector<int>,less<int> >H;
priority_queue<int,vector<int>,greater<int> >E;
il void read(int&);
int main(){
int n,K;
while(read(n),read(K),n&&K){
for(int i(1);i<=n;++i)read(a[i]);
for(int i(1),j,k;i<=n;++i){
while(H.size())H.pop();
while(E.size())E.pop();
H.push(a[i]),k=-a[i];
for(j=i+1;j<=n;++j){
if(a[j]<=H.top())
E.push(H.top()),H.pop(),H.push(a[j]),
k-=a[j],k+=E.top()<<1;
else E.push(a[j]),k+=a[j];
if((j-i+1)&1)k-=E.top()<<1,H.push(E.top()),E.pop();
m[i][j]=k+H.top()*((H.size()<<1)-(j-i+1));
}
}memset(dp,2,sizeof(dp)),dp[0][0]=0;
for(int i,j(1),k;j<=K;++j)
for(i=j;i<=n;++i)
for(k=0;k<i;++k)
if(dp[i][j]>dp[k][j-1]+m[k+1][i])
dp[i][j]=dp[k][j-1]+m[k+1][i];
printf("%d\n",dp[n][K]);
}
return 0;
}
il void read(int &x){
x&=0;ri char c;while(c=getchar(),c==' '||c=='\n'||c=='\r');
ri bool check(false);if(c=='-')check|=true,c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(check)x=-x;
}

最新文章

  1. 【BZOJ3282】Tree LCT
  2. Atitti 知识图谱构建方法attilax 总结
  3. mysql-5.7.17-winx64免安装版,win10环境下安装配置
  4. Genymotion模拟器环境搭建中的各种坑,终极解决办法
  5. 第12章 纤程(Fiber)
  6. JTAG的SWD接线方式
  7. windows下github pages + hexo next 搭建个人博客
  8. 请求--拦截器--action经过
  9. centos 6.X 安装node
  10. ActionBar隐藏修改图标和标题
  11. winxp iis5中修改最大连接数及添加多个站点
  12. ASP.NET Core:部署项目到Ubuntu Server
  13. dedecms v5.7 图片集“图集内容”无法调用的解决办法
  14. Java开发知识之Java的异常处理
  15. Python2 编码问题分析
  16. django发送邮件send_mail&amp;send_mass_mail
  17. mac环境下支持PHP调试工具xdebug,phpstorm监听
  18. Fortran+ OpenMP实现实例
  19. 报错:Exception in thread &quot;main&quot; com.typesafe.config.ConfigException$UnresolvedSubstitution
  20. WEB测试用例设计总结

热门文章

  1. Win10下安装erl和RabbitMQ踩坑【版本不兼容】
  2. 【单调队列优化】[CF372C] Watching Fireworks is Fun
  3. selenium+plantomJS
  4. jq-demo-拖拽
  5. Thymeleaf语法总结
  6. Java KMP算法代码
  7. 酷狗mac版如何新建歌单?酷狗mac版收藏歌单方法
  8. delphi xe10 安卓设备信息
  9. HTML+CSS项目——模拟京东网页
  10. 全球首个开放应用模型 OAM 开源