[TJOI2011]书架
时间:2019-11-06
本文章向大家介绍[TJOI2011]书架,主要包括[TJOI2011]书架使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意
将序列\(a_i\)分成任意\(k\)部分,要求一部分的\(a\)值和不超过\(m\);最小化(每段权值的最大值之和)\(,(n\leq 100000)\)
解法1
显然动态规划,设\(f_i\)表示处理前\(i\)个数的最小值,\(s\)为前缀和,状态转移:\(f_i=f_j+max(a_{j+1},a_{j+2}...a_i),(s_i-s_j\leq m)\)
考虑优化,首先,可转移的范围有单调性,可以用个指针\(O(n)\)做,不再赘述
维护线段树上的叶子:\(ans=min(f+max(a))\),\(mx=max(a)\),即\(f_i=min(ans)\)
每加入一个\(a_i\),考虑\(i\)前面连续比\(a_i\)小的一段\([l,i-1]\),这一段的\(mx\)更新为\(a_i\),\(ans=a[l]+mx\)
求\([l,i-1]\)可以用二分+查询,时间复杂度\(O(nlog^2n)\)
解法2
上面的二分是没有必要的,求前面第一个比\(a_i\)大的数显然是单调栈预处理,优化至\(O(nlogn)\)
Code
#include<bits/stdc++.h>
#define N 400005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,a[N],s[N];
int f[N],pre[N];
int mx[N<<2],ans[N<<2],sig[N<<2];
int st[N],top;//一个单调栈预处理pre
template <class T>
void read(T &x)
{
char c; int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void add_sign(int rt,int l,int r,int val)
{
sig[rt]=val;
mx[rt]=val;
ans[rt]=f[l]+val;
}
void pushdown(int rt,int l,int r)
{
if(!sig[rt]) return;
int mid=(l+r)>>1;
add_sign(rt<<1,l,mid,sig[rt]);
add_sign(rt<<1|1,mid+1,r,sig[rt]);
sig[rt]=0;
}
inline void pushup(int rt)
{
ans[rt]=Min(ans[rt<<1],ans[rt<<1|1]);
mx[rt]=Max(mx[rt<<1],mx[rt<<1|1]);
}
void mmx(int rt,int l,int r,int x,int y,int val)//更新最大值
{
if(x>y) return;
pushdown(rt,l,r);
if(x<=l&&r<=y) return add_sign(rt,l,r,val);
int mid=(l+r)>>1;
if(x<=mid) mmx(rt<<1,l,mid,x,y,val);
if(y>mid) mmx(rt<<1|1,mid+1,r,x,y,val);
pushup(rt);
}
void modify(int rt,int l,int r,int x)
{
if(l==r) { mx[rt]=a[l+1]; ans[rt]=f[l]+a[l+1]; return; }
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(x<=mid) modify(rt<<1,l,mid,x);
else modify(rt<<1|1,mid+1,r,x);
pushup(rt);
}
int query(int rt,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return ans[rt];
int mid=(l+r)>>1;
pushdown(rt,l,r);
int ret=2000000000;
if(x<=mid) ret=min(ret,query(rt<<1,l,mid,x,y));
if(y>mid) ret=min(ret,query(rt<<1|1,mid+1,r,x,y));
return ret;
}
int main()
{
read(n);read(m);
for(int i=1;i<=n;++i) read(a[i]),s[i]=s[i-1]+a[i];
for(int i=1;i<=n;++i)
{
while(top && a[st[top]]<=a[i]) --top;
pre[i]=st[top];//前面第一个比ai大的数
st[++top]=i;
}
modify(1,0,n,0);
int l=0;//可转移范围
for(int i=1;i<=n;++i)
{
while(s[i]-s[l]>m) ++l;
mmx(1,0,n,pre[i],i-1,a[i]);
f[i]=query(1,0,n,l,i-1);
modify(1,0,n,i);
}
cout<<f[n]<<endl;
return 0;
}
解法3
花式运用题目单调性,用单调栈/队列:博客\(O(n)\)
原文地址:https://www.cnblogs.com/Chtholly/p/11809005.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android右滑返回上一个界面的实现方法
- Android pull解析xml的实现方法
- Android实现QQ图片说说照片选择效果
- 一个简单的toolabar结合drawlayout使用方法
- 利用DrawerLayout和触摸事件分发实现抽屉侧滑效果
- Android App端与PHP Web端的简单数据交互实现示例
- Android开发实现读取assets目录下db文件的方法示例
- Android Textview实现颜色渐变滚动效果
- Android中fragment+viewpager实现布局
- android自动工具类TextUtils使用详解
- Android常用正则表达式验证工具类(实例代码)
- Android webview实现拍照的方法
- Android ListView自定义Adapter实现仿QQ界面
- Android webview旋转屏幕导致页面重新加载问题解决办法
- Android系统对话框使用详解(最详细)