Description

[0,x]中全是1,其余全是0,每个点有一个权值,求最坏情况下得到x的最小权值.

Sol

DP+单调队列.

首先就是一个 \(O(n^3)\) 的DP.

\(f[i][j]\) 表示x在 \(i,j\) 之间的最小权值.

转移就是 \(f[i][j]=min \{ max \{ f[i][k-1],f[k+1][j] \} +a[k] \} ,i\leqslant k\leqslant j\) 。

一个记搜就是 \(O(n^3)\) 的.

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define N 2005
int n;int a[N],f[N][N];
inline int in(int x=0,char ch=getchar(),int v=1){
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v; }
int DFS(int l,int r){
if(l>r) return 0;if(l==r) return f[l][r]=a[l];
int &ans=f[l][r];if(~ans) return ans;ans=0x7fffffff;
for(int i=l;i<=r;i++) ans=min(ans,max(DFS(l,i-1),DFS(i+1,r))+a[i]);
return ans;
}
int main(){
n=in();for(int i=1;i<=n;i++) a[i]=in();
memset(f,-1,sizeof(f));
cout<<DFS(1,n);return 0;
}

然后考虑优化,我们发现其实可以把 \(max\) 去掉.

因为 \(f[i][j]\) 固定任意一段,随区间长度增长是单调递增的.

那么关于分割点 \(g\) 我们就可以二分了.

然后就是可以维护 \(f[i][k-1]+a[k],i\leqslant k\leqslant g\) 和 \(f[k+1][j]+a[k], g < k\leqslant j\) .

这个可以通过建以 \(i\) 和 \(j\) 为端点的线段树向左向右来维护.

复杂度 \(O(n^2logn)\) .差不多可以通过本题了.

但是我们发现还可以继续优化,因为 \(g[i][j-1] \leqslant g[i][j],g[i][j] \leqslant g[i+1][j]\) .

这个过程是 \(O(n)\) 的.

然后维护最小值就可以用单调队列.

一开始我非常的naive,只用了2个队列来维护,然后写个程序来对拍直接gg.

#include<cstdio>
#include<iostream>
using namespace std; const int N = 2005; int n,t[N];
int f[N][N];
int q1[N],h1,t1;// [i,g]
int q2[N],h2,t2;// (g,j] inline int in(int x=0,char ch=getchar(),int v=1){
while(ch!='-' && (ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();
while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v; } int main(){
// freopen("in.in","r",stdin);
n=in();
for(int i=1;i<=n;i++) t[i]=in(); for(int i=n;i;i--){
f[i][i]=t[i],f[i][i-1]=0;
h1=h2=1,t1=t2=0;
q1[++t1]=i; int g=i;
// int tmpm=i;
for(int j=i+1;j<=n;j++){
//q1 - 加入t[j]
while(h1<=t1 && f[i][q1[t1]-1]+t[q1[t1]] > f[i][j-1]+t[j]) t1--;
q1[++t1]=j; //分割点
for(;g<j && f[i][g-1] < f[g+1][j];g++){
//q1 del g
if(q1[h1] == g) h1++;
//q2 add g
while(h2<=t2 && f[q2[t2]+1][j]+t[q2[t2]] > f[g+1][j]+t[g]) t2--;
q2[++t2]=g;
// if(f[tmpm][j]+t[tmpm] > f[g+1][j]+t[g]) tmpm=g;
} //计算f[i][j]
f[i][j]=min(f[i][q1[h1]-1]+t[q1[h1]],f[q2[h2]+1][j]+t[q2[h2]]);
// f[i][j]=min(f[i][j],f[tmpm][j]+t[tmpm]);
}
// for(;h2<=t2;h2++) f[i][n]=min(f[i][n],f[q2[h2]+1][n]+t[q2[h2]]);
} // for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) printf("%d%c",f[j][j+i-1]," \n"[j==n-i+1]); cout<<f[1][n]<<endl;
return 0;
}

我们重新来看一下维护的东西.

\(f[i][k-1]+a[k],i\leqslant k\leqslant g[i][j]\) \(f[k+1][j]+a[k], g[i][j] < k\leqslant j\) .

可以发现一个 \(i\) 是固定的,第二个 \(j\) 是固定的,我们可以用这个性质来维护.

就是用 \(n+1\) 个单调队列来维护,用一个单调队列维护 \(i\) 随 \(j\) 增长时的最小值.

其他的维护右端点 \(j\) 固定时,随 \(i\) 递减的最小值.

注意一下入队和出队就可以了.

对于 \(i\) 固定时,需要出队的是 \((g[i-1][j],g[i][j])\) ,入队的是 \(j\) .

对于 \(j\) 固定时,需要出队的是 \((g[i+1][j],g[i][j])\) ,入队的是 \(i\) .

还有一点就是 \(f[i][j]\) 用到 \(f[i][k-1],f[k+1][j]\) ,所以 \(i\) 需要倒着枚举.

这个样子 复杂度就变成了 \(O(n^2)\) 啦!

PS:双倍经验 BZOJ 2412

Code

/**************************************************************
Problem: 2448
User: BeiYu
Language: C++
Result: Accepted
Time:1316 ms
Memory:48420 kb
****************************************************************/
#include<cstdio>
#include<iostream>
using namespace std; const int N = 2005;
#define A(x) (f[i][x-1]+a[x])
#define B(x) (f[x+1][j]+a[x]) int n,a[N];
int f[N][N],g[N][N];
int q[N][N],h[N],t[N]; inline int in(int x=0,char ch=getchar(),int v=1){
while(ch!='-' && (ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();
while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v; } int main(){
// freopen("in.in","r",stdin);
n=in();
for(int i=1;i<=n;i++) a[i]=in(); for(int i=n;i;--i){
f[i][i]=a[i],g[i][i]=i; //f[i][j]=min{ f[i][k-1]+t[k] },g[i][j]<=k<=j; =>q[0]
//f[i][j]=min{ f[k+1][j]+t[k] },i<=k<g[i][j]; =>q[j] h[0]=1,t[0]=0;
h[i]=1,t[i]=0;
q[i][++t[i]]=i; for(int j=i+1;j<=n;++j){
//g[i][j]
g[i][j]=g[i][j-1];
while(g[i][j]<j && f[i][g[i][j]-1] < f[g[i][j]+1][j]) ++g[i][j]; //q[0].pop g[i][j-1]--(g[i][j]-1)
for(int k=g[i][j-1];k<g[i][j];++k)
if(q[0][h[0]] == k) ++h[0];
//j->q[0]
while(h[0]<=t[0] && A(q[0][t[0]]) > A(j)) --t[0];
q[0][++t[0]]=j; //q[j].pop g[i+1][j]-g[i][j]
for(int k=g[i+1][j];k>=g[i][j];--k)
if(q[j][h[j]] == k) ++h[j];
//i->q[j]
while(h[j]<=t[j] && B(q[j][t[j]]) > B(i)) --t[j];
q[j][++t[j]]=i; //f[i][j]
f[i][j]=min(A(q[0][h[0]]),B(q[j][h[j]])); }
} // for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) printf("%d%c",g[j][j+i-1]," \n"[j==n-i+1]);
// cout<<"***"<<endl;
// for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) printf("%d%c",f[j][j+i-1]," \n"[j==n-i+1]); cout<<f[1][n]<<endl;
return 0;
}

  

BZOJ 2448: 挖油的更多相关文章

  1. bzoj千题计划235:bzoj2448: 挖油

    http://www.lydsy.com/JudgeOnline/problem.php?id=2448 一遍过,嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎嘎,O(∩_∩)O~ 题意是最小化最大值 设计区间dp dp[i ...

  2. BZOJ2448 : 挖油

    $f[i][j]$表示仅考虑$[i,j]$区间的答案,则 $f[i][j]=\min(\max(f[i][k-1],f[k+1][j])+a[k]),i\leq k\leq j$ 维护出$\max$的 ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. OI题目类型总结整理

    ## 本蒟蒻的小整理qwq--持续更新(咕咕咕) 数据结构 数据结构 知识点梳理 数据结构--线段树 推荐yyb dalao的总结--戳我 以后维护线段树还是把l,r写到struct里面吧,也别写le ...

  5. 区间DP复习

    区间DP复习 (难度排序:(A,B),(F,G,E,D,H,I,K),(C),(J,L)) 这是一个基本全在bzoj上的复习专题 没有什么可以说的,都是一些基本的dp思想 A [BZOJ1996] [ ...

  6. 【BZOJ】【1177】【APIO2009】Oil

    DP 找出三个正方形,可以转化为将整个油田切成三个矩形块,每块中各找一个正方形区域,切的形式只有6种,分类更新ans即可 题解:http://trinklee.blog.163.com/blog/st ...

  7. 【BZOJ】【1017】【JSOI2008】魔兽地图Dotr

    树形DP 一开始想:f[i][j]表示以 i 为根的子树,花 j 块钱能得到的最高力量值,结果发现转移的时候没法保证叶子结点的数量限制TAT 只好去膜拜题解了……在这里贴两篇泛型背包的文章吧:< ...

  8. 【BZOJ】【1833】【ZJOI2010】count 数字计数

    数位DP Orz iwtwiioi 学习了一下用记忆化搜索来捉题的新姿势……但没学会TAT,再挖个坑(妈蛋难道对我来说数位DP就是个神坑吗……sigh) //BZOJ 1833 #include< ...

  9. 【BZOJ】【3093】【FDU校赛2012】A Famous Game

    概率论 神题不会捉啊……挖个坑先 orz 贾教 & QuarterGeek /********************************************************* ...

随机推荐

  1. 自然语言6_treebank句子解析

    #英文句子结构分析 import nltkfrom nltk.corpus import treebankt = treebank.parsed_sents('wsj_0001.mrg')[1]t.d ...

  2. DllImport dll中有些啥函数 及 dll中是否用到了别的dll

    在加载dll的时候不知道dll中有哪些接口怎么办,或者使用别人封装的东西时报出类似于“无法在 DLL“XXX.dll”中找到名为“XXX函数”的入口点.”     1.通过LordPE这个软件来看dl ...

  3. Centos7.X 源码编译安装subversion svn1.8.x

    说明:SVN(subversion)的运行方式有两种:一种是基于Apache的http.https网页访问形式:还有一种是基于svnserve的独立服务器模式.SVN的数据存储方式也有两种:一种是在B ...

  4. 2015年最全的移动WEB前端UI框架

    目前,众多互联网公司APP都嵌入了大量的HTML5,移动端的开发越来越重视,HTML5的运用场景也越来越多了.在移动WEB开发的过程中,使用合适的移动WEB UI框架可以大大提升我们的开发效率.下面P ...

  5. VC----对话框Dialog

    一个非模态对话框,当作主窗体的创建:(符合窗口创建的步骤) 第一步:补充一个模板,在RC脚本文件文件中,这是和普通窗口不一样的地方.这利益于编译器和链接器的支持呀. #include "wi ...

  6. Unity3D热更全书

    http://www.cnblogs.com/crazylights/p/3897742.html

  7. thinkphp传递参数

    php文件输出 U() 跳转地址, echo U('Index/index',array('uid'=>1,'username'=>'wang','time'=>165465121) ...

  8. 商城常用css分类代码

    如图: 原代码如下: <div class="allMerchan bgnone"> <h2 class="ttlm_category"> ...

  9. Quartz.NET总结(一)入门

    前段时间,花了大量的时间,将原先的计划任务,切换到Quartz.NET来进行管理.原先的后台定时服务都是通过计划任务来实现的,但是随着业务增长,计划任务也越来越多,每个后台服务,都得创建一个计划任务. ...

  10. Blue tooth

    一 . nordic BLE4.0 1.开发nordic的应用需要安装支持keil的pack库和插件 2.nordic的SDK很完整,实例涵盖了几乎所有的应用 https://www.nordicse ...