蒟蒻的 \(\operatorname{DP}\) 很菜,\(\operatorname{SO}\) 我准备上一套二分的玄学操作。

简单的二分答案

二分主要是用来解决一些最值问题,它可以有效的优化暴力,使复杂度减少到 \(O(logn)\)。

我先给大家介绍一下二分里一个常用的模型:左闭右开。

如图,这就是个典型的左闭右开模型。其中,黄色部分可以表示成一个区间 \([1,9\}\), 其中包含了数字 \(1\)~\(8\),而并非包含 \(9\),在二分里我们把它称之为右开

那么回过头来看 \(1\),它是区间内的值,也是开始的值,即 \(a.begin()\),在二分里我把它称为左闭

所以,在一个左闭右开的模型中,区间 \([ll,rr\}\) 表示 \(ll\) 至 \(rr-1\) 内所有包含的值。

那么回到二分里,我们是不是可以把左边的 \(ll\) 标记成一定可以满足的值。右边的 \(rr\) 标记成一定不可以满足的值。那么我们就可以通过 \(mid=(ll+rr)/2\) 来取得中间值不断更新区间。如果 \(mid\) 可行,则 \(ll\) 至 \(mid\) 都可行,于是区间就缩小到了 \([mid,rr\}\)。如果 \(mid\) 不可行,则 \(mid\) 至 \(rr\) 都不可行,于是区间就缩小到了 \([ll,mid\}\)。

所以我们可以用一个 \(\operatorname{while}\) 循环来不断更新区间。直到 \(ll+1=rr\),说明 \(ll\) 可行,\(ll+1(rr)\) 不可行,则停止。最后的 \(ll\) 就是一定可行的最大情况。

这里给个左闭右开的简单模板:

while(ll+1<rr) { //二分答案
int mid=(ll+rr)>>1;
if(check(mid)) rr=mid;
else ll=mid;
}

知道了左闭右开,左开右闭也不难理解了。在一个左开右闭的模型中,区间 \(\{ll,rr]\) 表示 \(ll+1\) 至 \(rr\) 内所有包含的值。

所以,我们可以把左边的 \(ll\) 标记成一定不可以满足的值,右边的\(rr\) 标记成一定可以满足的值。再通过 \(mid\) 不断更新区间,直到 \(ll+1=rr\)。最后的 \(rr\) 就是一定可行的最小情况。

关于本题

题意:\(n\) 本书 \(m\) 个人,每人抄连续的几本书(不能不抄),求最后时间用的最多的那个人。

二分解题思路:

套一个表示复制时间的区间,逐一 \(\operatorname{check}\) 是否可行。采用左开右闭的方式,一开始 \(ll=0\) 则一定不可行,\(rr\) 等于这些时间的总和则一定可行。再不断取 \(mid\) 即可。

如何 \(\operatorname{check}\):

二分中的 \(\operatorname{check}\) 须按题意模拟,本题中,我们可以通过二分给出的这个时间,来判断能否满足 \(m\) 个人就足够干完。所以循环跑一遍就行啦,主要是一些细节可以参考我的代码。

输出过程:

如果已经二分得到了最小的复制时间 \(rr\),我们就能倒推把每个人的复制区间找出来。但是由于要尽可能让前面的人少抄写,我们可以倒着循环,让后面的人复制到最大化,前面的人自然就少抄了。

\(\operatorname{Code:}\)

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m,sum,a[N],s[N],t[N],len;
bool check(int x) {
int tot=0,sum=1; //tot表示临时时间总和,sum表示人数
for(int i=1;i<=n;i++) {
if(a[i]>x)return false; //如果打印一本的时间就不够,直接返回false
if(tot+a[i]<=x) tot+=a[i]; //连续当前的时间
else tot=a[i],sum++; //时间不够用了,在来一个人
}
return sum<=m;
}
void Point(int x) {
int tot=0,last=n;
a[0]=INT_MAX/2; //边界
for(int i=n;i>=0;i--) {
if(tot+a[i]<=x) tot+=a[i];
else {
len++, s[len]=i+1, t[len]=last; //记录区间
last=i, tot=a[i];
}
}
for(int i=len;i>=1;i--) cout<<s[i]<<" "<<t[i]<<"\n";
}
void Exit() {exit(0);}
int main() {
ios::sync_with_stdio(false);
cin>>n>>m;
if(m==0) Exit();
for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; int ll=0,rr=sum;
while(ll+1<rr) { //二分答案
int mid=(ll+rr)>>1;
if(check(mid)) rr=mid;
else ll=mid;
}
Point(rr);
return 0;
}

\(\operatorname{Update}\) \(\operatorname{On}\) \(\operatorname{2019.03.04}\)

题解 洛谷P1281 【书的复制】的更多相关文章

  1. 洛谷 P1281 书的复制 题解

    P1281 书的复制 题目背景 大多数人的错误原因:尽可能让前面的人少抄写,如果前几个人可以不写则不写,对应的人输出0 0. 不过,已经修改数据,保证每个人都有活可干. 题目描述 现在要把m本有顺序的 ...

  2. 洛谷 P1281 书的复制

    书的复制 Code: #include <iostream> #include <cstdio> #include <cstring> using namespac ...

  3. 洛谷P1281 书的复制

    题目描述 现在要把m本有顺序的书分给k给人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一.第三.第四本书给同一个人抄写. ...

  4. 【洛谷P1281 书的复制】二分+动态规划

    分析 两个做法,一个DP,一个是二分. 二分:也就是二分枚举每个人分到的东西. DP:区间DP F[I][J]表示前i本书分给j个人用的最短时间 由于每一次j的状态由比j小的状态得出,所以要先枚举j, ...

  5. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  6. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  7. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  8. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  9. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

随机推荐

  1. 最新 淘友天下java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.淘友天下等10家互联网公司的校招Offer,因为某些自身原因最终选择了淘友天下.6.7月主要是做系统复习.项目复盘.Leet ...

  2. Mac和window实现双向数据传输

    Mac和window实现双向数据传输 总体步骤:第一步,在window上设置开发访问权限,然后选择要共享的磁盘或者文件夹第二步,在Mac上使用 Finder里面的网络,command+K,选择一个IP ...

  3. SpringBoot系列教程web篇之如何自定义参数解析器

    title: 190831-SpringBoot系列教程web篇之如何自定义参数解析器 banner: /spring-blog/imgs/190831/logo.jpg tags: 请求参数 cat ...

  4. hdu 2841 题解

    题目 题意:就是问在一个$ n* m $的矩阵中站在 $ (0,0) $ 能看到几个整数点. 很明显如果有两个平行向量 $ \vec{a}=(x_1,y_1) $ ,$ \vec{b}=(x_2,y_ ...

  5. Nvidia Jetson TX2开发板学习历程(1)- 详细开箱、上电过程

    考试周已经结束了,开发板也已经到了.希望借着这个假期能够好好的利用这块开发板学习Linux系统以及Tensorflow的相关知识. 我打算将学习历程通过博客的方式写出来,作为自己的笔记,也可以供以后拿 ...

  6. 【C#】上机实验九

    1. 设计一个Windows登陆窗体应用程序,能够实现根据现有表中数据模拟登陆,并设置相关属性,具体界面如下. 可能使用到的类: (1)SqlConnection (2)SqlCommand (3)S ...

  7. C# vb .net实现饱和度调整特效滤镜

    在.net中,如何简单快捷地实现Photoshop滤镜组中的饱和度调整呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一 ...

  8. Xcodeproj相关以及删除 多层文件夹、库、资源逻辑

    一.介绍Xcodeproj是CocoaPods用ruby开发的一个插件库,可以用来新建.修改Xcode工程. 二.wiki和资源Xcodeproj wiki   :https://www.rubydo ...

  9. node+mysql+vue+express项目搭建

    第一步:项目搭建之前首先需要安装node环境和MySQL数据库. 在已经完成上述的条件下开始进行以下操作: npm install @vue/cli -g   (-g 代表全局安装) 初始化项目  v ...

  10. DDL 操作数据库

    DDL 操作数据库:常用的操作 CRUD 一.C(create)创建 1.创建数据库 create database 数据库名称; 2.创建数据库,判断是否存在,再创建(如果存在,就不再创建) cre ...