【基础算法】第三章 二分算法

例一 数列分段

题目描述

对于给定的一个长度为N的正整数数列A,现在将其分成M段,并要求每段连续,且每段和的最大值最小。

输入格式

第1行包含两个正整数N,M。

第2行包含N个空格隔开的非负整数A。

输出格式

仅包含一个正整数,即每段和最大值最小为多少。

样例输入

  5 3
4 2 4 5 1

样例输出

6

分析

题中出现类似“最大值最小”的含义,这是答案具有单调性的最常见、最典型 的特征之一。设最优解为S,因为S的最优性如果要求每段和可以>S,那么一定存在一种划分方案使得总段数不超过M。因此答案就处于分段可行性的分界点上。

样例代码

bool check(int limit){
int cnt=1;sum=0;
for(int i=1;i<=n;i++){
if(sum+a[i]<=n;i++){
sum+=a[i];
}
else cnt++,sum=a[i];
}
return cnt<=m;
}

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],l,r,mid,ans; bool check(int x){
int sum=0,num=0;
for(int i=1;i<=n;i++)
{
if(sum+a[i]<=x)
sum+=a[i];
else sum=a[i],num++;
}
return num>=m;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i],l=max(l,a[i]),r+=a[i];
while(l<=r){
mid=l+r>>1;
if(check(mid))
l=mid+1;
else
r=mid-1;
}
cout<<l;
return 0;
}

例二 防具布置

题目描述

现在有N组防具。 我们可以认为防线是一维的,那么每一组防具都分布在防线的某一段上,并且同一组防具是等距离排列的。 也就是说,我们可以用三个整数 和 来描述一组防具,即这一组防具布置在防线的S,S+D,S+2D...S+KD位置上。 若一个位置上的防具数量为奇数,则我们称这个位置有破绽,但是整个防线上有且仅有一个位置有破绽或根本没有破绽。请你求出破绽的位置,或是确定防线没有破绽。

输入格式

第一行是一个整数T,表示有T组互相独立的测试数据。

每组数据的第一行是一个整数N。

之后N行,每行三个整数S,E,D,代表第i组防具的三个参数,数据用空格隔开。

输出格式

对于每组测试数据,如果防线没有破绽,输出一行 There's no weakness.。

否则在一行内输出两个空格分隔的整数P和C,表示在P位置 有C个防具。当然C应该是奇数。

样例输入

  3
2
1 10 1
2 10 1
2
1 10 1
1 10 1
4
1 10 1
4 4 1
1 5 1
6 10 1

样例输出

1 1

There's no weakness.

4 3

分析

首先,若S(2^(31)-1)为偶数,则整道防线没有破绽。

否则,设破绽的位置为P,故只有P上有奇数个防具,其他位置上都有偶数个,则对于x<p,S(x)均为偶数,对于x>=P,S(x)均为奇数。

Code

#include <bits/stdc++.h>
#define N 200010
using namespace std;
int T, n;
long long s[N], e[N], d[N], l, r, mid, ans; long long f(long long x){
long long sum=0;
for (int i=1;i<=n;i++)
if (s[i]<=x)
sum+=(min(x,e[i])-s[i])/d[i]+1;
return sum;
}
void work ()
{
cin>>n;
for (int i = 1; i <= n; i++)
cin>>s[i]>>e[i]>>d[i];
if (f((long long)2147483647)%2==0){
printf("There's no weakness.\n");
return;
}
l=ans=1,r=(long long)2147483647;
while (l < r)
{
mid = (l + r) / 2;
if (f(mid) % 2 == 1) r = mid;
else l=mid+1;
}
cout<<r<<" "<<f(r)-f(r-1)<<endl;
} int main()
{
cin>>T;
while(T--)
work ();
return 0;
}

例三 最大均值

题目描述

给定正整数序列A,求一个平均数最大的,长度不小于L的(连续的)子段。

输入格式

第一行两个整数N和L。

接下来N行,每行输入一个正整数A。

输出格式

输出一个整数,表示平均值的最大值乘以1000再向下取整之后得到的结果。

样例输入

  10 6
6
4
2
10
3
8
5
9
4
1

样例输出

6500

分析

注意到答案具有单调性,考虑二分答案,判定“是否存在一个长度不小于L的子段,平均值不小于mid”。

如果把序列里每个数都减去二分的值,就进一步转化为“是否存在一个长度不小于L的子段,子段和非负”。

然后只需要检查一下最大子段和是否为非负数,就可以确定二分上下界的变化范围了。

Code

#include <bits/stdc++.h>
using namespace std;
const double N=1e-5;
int n,L;
double a[100004],b[100004],sum[100004];
bool check(double num){
for(int i=1;i<=n;i++)
b[i]=a[i]-num;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+b[i];
double ans=-1e10;
double v=1e10;
for(int i=L;i<=n;i++){
v=min(v,sum[i-L]);
ans=max(ans,sum[i]-v); }
return ans>=0;
}
int main(){
double l=-1e6,r=1e6;
cin>>n>>L;
for(int i=1;i<=n;i++)
cin>>a[i];
while(l+N<r){
double mid=(l+r)/2;
if(check(mid))
l=mid;
else r=mid;
} cout<<int (r*1000)<<endl;
}

【ybtoj】二分算法例题的更多相关文章

  1. python-Day4-迭代器-yield异步处理--装饰器--斐波那契--递归--二分算法--二维数组旋转90度--正则表达式

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  2. what' the python之递归函数、二分算法与汉诺塔游戏

    what's the 递归? 递归函数的定义:在函数里可以再调用函数,如果这个调用的函数是函数本身,那么就形成了一个递归函数. 递归的最大深度为997,这个是程序强制定义的,997完全可以满足一般情况 ...

  3. Python练习-递归二分算法

    # 编辑者:闫龙 #递归,二分算法演示 l = [i for i in range(1,100)]#定义一个列表l,并追加1-99的所有数字 def FindNum(num,l):#定义函数FindN ...

  4. Java冒泡,快速,插入,选择排序^_^+二分算法查找

    这段时间在学Java,期间学到了一些排序和查找方法.特此写来和大家交流,也方便自己的日后查看与复习. 1.下边是Java的主类: public class Get { public static vo ...

  5. #AcWing系列课程Level-2笔记——4. 浮点数二分算法

    浮点数二分算法 编写浮点数二分,记住下面的思路,代码也就游刃有余了! 1.首先找到数组的中间值,mid=(left+right)>>1,区间[left, right]被划分成[left, ...

  6. #AcWing系列课程Level-2笔记——3. 整数二分算法

    整数二分算法 编写整数二分,记住下面的思路,代码也就游刃有余了! 1.首先找到数组的中间值,mid=(left+right)>>1,区间[left, right]被划分成[left, mi ...

  7. java 的二分算法

    二分算法 就是在 一组 有序 数组中 通过中间值(数组中间的那个数字)的方法 找到 某个数的下标,如果大于中间值 ,则在中间值与最大值之间 的中间值再比较. public class two { // ...

  8. 算法leetcode二分算法

    二分算法通常用于有序序列中查找元素: 有序序列中是否存在满足某条件的元素: 有序序列中第一个满足某条件的元素的位置: 有序序列中最后一个满足某条件的元素的位置. 思路很简单,细节是魔鬼. 一.有序序列 ...

  9. 编程思想与算法leetcode_二分算法详解

    二分算法通常用于有序序列中查找元素: 有序序列中是否存在满足某条件的元素: 有序序列中第一个满足某条件的元素的位置: 有序序列中最后一个满足某条件的元素的位置. 思路很简单,细节是魔鬼. 二分查找 一 ...

随机推荐

  1. idea 开启 tomcat 热部署 的 具体流程 和 使用方式

    1前言 一直以来,使用idea做web开发修改html.jsp.js文件后,必须手动重新部署tomcat,最少都有等个6 -10 秒, 甚至有时候还提示找不到某个编译文件报错,重新编译整个项目,那得等 ...

  2. 新增访客数量MR统计之数据库准备

    关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...

  3. js字符串首字母大写的不同写法

    写法一: let name = 'hello' name.charAt(0).toUpperCase() + name.slice(1) 写法二: let name = 'hello' name.sl ...

  4. [未完] Linux 4.4 USB —— spiflash模拟usb大容量存储设备 调试记录 Gadget Mass Stroage

    linux 4.4 USB Gadget Mass Stroage 硬件平台: licheepi nano衍生 调试记录 驱动信息 │ This driver is a replacement for ...

  5. 基于Jenkins+Maven+Gitea+Nexus从0到1搭建CICD环境

    在传统的单体软件架构中,软件开发.测试.运维都是以单个进程为单位. 当拆分成微服务之后,单个应用可以被拆分成多个微服务,比如用户系统,可以拆分成基本信息管理.积分管理.订单管理.用户信息管理.合同管理 ...

  6. R语言服务器程序 Rserve详解

    R语言服务器程序 Rserve详解 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大. R语言作为统计学一门语言,一直在小众领域闪耀着光芒.直到 ...

  7. [C 语言基础] 如何调用不同文件中的函数

    很多时候需要将实现不同功能的函数或者与某个模块有关的函数写在一个文件里.这样有两个好处: 1. 方便以后调用:以后需要用到这个模块,或者这类函数,直接将相关文件复制过去,再稍微修改一下就能应用于不同场 ...

  8. SaltStack 的基本概念与工作原理 架构设计

    随着云计算技术的快速普及与发展,越来越多的企业开始学习和搭建自己的云平台代替传统的 IT 交付模式,企业的 IT 环境也随之越来越复杂,常规的运维方法与技术已经无法满足现在云环境中系统的配置与变更.基 ...

  9. Typora基础快捷键使用流程

    Typora简介 Typora是一个所见即所得的Markdown格式文本编辑器,支持windows.macOS和GNU\Linux操作系统,包括对GitHub Flavored Markdown扩展格 ...

  10. Atcoder ARC-060

    ARC060(2020.7.8) A 背包板子 B 首先感觉这个东西应该不能直接 \(O(1)\) 算出来,那么复杂度应该就是 \(O(\log n), O(\sqrt{n}), O(\sqrt{n} ...