Hdu6606 Distribution of books

题意

把一段连续的数字分成k段,不能有空段且段和段之间不能有间隔,但是可以舍去一部分后缀数字,求\(min(max((\sum ai ))\)其中\(\sum ai\)为一段的数字和

分析

最小化最大值问题通常我们要想到二分,所以答案的求法我们就解决了,但是二分我们怎么check呢?这个时候一点思路都没有,我们考虑暴力的算法,设dp[i]表示从1--i最多可以分成多少段,怎么转移,什么情况下可以转移呢?

显然\(dp[i]=max(dp[j]+[sum[i]-sum[j]<=x])\)这样就能取到最多段了,但是这个转移的写法是\(O(n^2)\)的暴力算法,显然不满足题目的复杂度,这就到了这个题目的难点了,如何对dp进行优化,对dp进行优化的方式有多种,单调栈、平行四边形、线段树、主席树等。

关于dp优化:https://blog.csdn.net/qq_35649707/article/details/77834685

这里因为取值满足不等式,而不等式所表示的值域就是天然的区间,区间问题肯定非线段树莫属。我们采用线段树优化,使用权值线段树的节点对应离散化后的sum值,从而维护dp的值,由不等\(sum[i]-sum[j]<=x\)我们转化为\(sum[i]-x<=sum[j]\)即只要找第一个满足该不等式的sum,然后在\([j,m]\)中找最大的dp值即可转移,复杂度就优化到了\(O(nlognlogn)=O(nlog^2n)\)

#include<bits/stdc++.h>
#define pb push_back
#define F first
#define S second
#define pii pair<int,int>
#define mkp make_pair
typedef long long ll;
using namespace std;
const int maxn=2e5+5;
int tr[maxn<<2];
int a[maxn];
ll sum[maxn],v[maxn];
int t,n,k,flag,cnt=0,sz;
void build(int o,int l,int r){
tr[o]=-maxn;
if(l==r)return ;
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
}
void update(int o,int l,int r,int p,int v){
if(l==r)tr[o]=max(tr[o],v);
else {
int mid=l+r>>1;
if(mid>=p)update(o<<1,l,mid,p,v);
else update(o<<1|1,mid+1,r,p,v);
tr[o]=max(tr[o<<1],tr[o<<1|1]);
}
}
int query(int o,int l,int r ,int x,int y){
if(x<=l&&y>=r)return tr[o];
int mid=l+r>>1;
int ans=-maxn;
if(mid>=x)ans=max(ans,query(o<<1,l,mid,x,y));
if(mid<y)ans=max(ans,query(o<<1|1,mid+1,r,x,y));
return ans;
}
bool check(ll x){
build(1,1,sz);
for(int i=1;i<=n;i++){
int l=lower_bound(v+1,v+1+sz,sum[i]-x)-v;
int id=lower_bound(v+1,v+1+sz,sum[i])-v;
//cout<<" i "<<i<<" l "<<l<<" id "<<id<<" sum-x "<<sum[i]-x<<endl;
if(l>sz){
if(sum[i]<=x)
update(1,1,sz,id,1);
}
else {
int t=query(1,1,sz,l,sz);
//cout<<i<<" t "<<t<<endl;
if(t==-maxn){
if(sum[i]<=x)
update(1,1,sz,id,1);
}
else
update(1,1,sz,id,t+1);
}
}
//cout<<query(1,1,sz,1,sz)<<endl;
return query(1,1,sz,1,sz)>=k;
}
int main(){
scanf("%d",&t);
while(t--){
cnt=1;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
v[cnt++]=(sum[i]);
}
cnt--;
sort(v+1,1+v+cnt);
sz=unique(v+1,v+1+cnt)-v-1;
// for(int i=1;i<=sz;i++)cout<<v[i]<<" ";
// cout<<endl;
//cout<<sz<<endl;
ll l=-1e14;
ll r=-l;
ll ans=1e15;
while(l<=r){
ll mid=l+r>>1;
//cout<<l<<" "<<r<<endl;
if(check(mid)){
ans=min(ans,mid);
r=mid-1;
}
else l=mid+1;
}
printf("%lld\n",ans);
}
return 0;
}

最新文章

  1. 前端学PHP之命名空间
  2. 2D几何变换
  3. C#获取文件时间
  4. 黑马程序员——JAVA基础之单列设计模式
  5. init: Associated with Deployer &#39;Catalina:type=Deployer,host=localhost&#39;
  6. Android实例-退出程序(XE8+小米2)
  7. HDU-1874 畅通工程续 (最短路径启蒙题)
  8. 那些容易忽略的事4-(正则表达式反向引用\n)
  9. 转: seajs知识点与cmd规范
  10. 《收藏》对servlet原理讲解特别详细
  11. 通过Excel生成PowerDesigner表结构设计
  12. model 字段参数 choice
  13. 吴恩达课后作业学习2-week3-tensorflow learning-1-基本概念
  14. docker 12 docker容器数据卷
  15. c++入门之 深入cin
  16. 【jQuery Demo】图片切换效果整理
  17. docker 镜像存放路径的修改
  18. 记录清除wnTKYg挖矿工木马(守护进程ddg.xxxx)的过程
  19. ubuntu安装rubyOnRails
  20. sudo执行脚本找不到环境变量和命令

热门文章

  1. gulp常用插件之cssnano使用
  2. Cows Of The Round Table【DFS】
  3. PAT (Basic Level) Practice (中文)1023 组个最小数 (20 分) (排序)
  4. php 对象、json 、XML、数组互转
  5. 手把手带你开发一款 IIS 模块后门
  6. deepin开机自动启动服务备忘
  7. 推荐7个GitHub项目
  8. Ionic 使用 NFC
  9. Ecshop各个页面文件介绍,主要文件功能说明
  10. 三、linux环境的搭建1(oracle、ssh、jdk、mysql、samba、tomcat)