二分答案

不理解  先写上

面对整数时的万能二分(近似万能)

int binary(int n)
{
    int l = 1, r = maxn, ans = 0;
    while(l <= r)
      {
        int mid = (l + r) >> 1;
        if(c[mid] > a[n]) ans = mid, l = mid + 1;  //判断条件与ans记录位置因题而异
        else r = mid - 1;
      }
    return ans;
}

P2678 跳石头 题解

题目背景

一年一度的“跳石头”比赛又要开始了!

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NNN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MMM 块岩石(不能移走起点和终点的岩石)。

输入输出格式

输入格式:

 

第一行包含三个整数 L,N,ML,N,ML,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1L \geq 1L≥1 且 N≥M≥0N \geq M \geq 0N≥M≥0。

接下来 NNN 行,每行一个整数,第 iii 行的整数 Di(0<Di<L)D_i( 0 < D_i < L)Di​(0<Di​<L), 表示第 iii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

 

输出格式:

 

一个整数,即最短跳跃距离的最大值。

 

输入输出样例

输入样例#1: 复制

25 5 2 
2
11
14
17 
21

输出样例#1: 复制

4

说明

输入输出样例 1 说明:将与起点距离为 222和 141414 的两个岩石移走后,最短的跳跃距离为 444(从与起点距离 171717 的岩石跳到距离 212121 的岩石,或者从距离 212121 的岩石跳到终点)。

另:对于 20%20\%20%的数据,0≤M≤N≤100 ≤ M ≤ N ≤ 100≤M≤N≤10。

对于50%50\%50%的数据,0≤M≤N≤1000 ≤ M ≤ N ≤ 1000≤M≤N≤100。

对于 100%100\%100%的数据,0≤M≤N≤50,000,1≤L≤1,000,000,0000 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,0000≤M≤N≤50,000,1≤L≤1,000,000,000。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int L, n, m;
int a[50005];
int check(int mid)
{
     int last=0, count=0;
     for(int i=0;i<n;i++)
     {
         if(a[i]-last<mid)
         {
              count++;
         }
         else
         {
             last=a[i];
         }
     }
     if(L-last<mid)
     count++;
     if(count<=m)
     return 1;
     else
     return 0;
}
int main()
{
    while(scanf("%d%d%d", &L, &n, &m)!=EOF)
    {
         for(int i=0;i<n;i++)
         {
             scanf("%d", &a[i]);
         }
         sort(a, a+n);
         int l=1, r=L;
         int ans;
         while(l<=r)
         {
              int mid=(l+r)/2;
              if(check(mid))
              {
                 ans=mid;
                 l=mid+1;
              }
              else
              r=mid-1;
         }
         printf("%d\n", ans);
    }
    return 0;
}

 

小明的花费预算

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description

小明终于找到一份工作了,但是老板是个比较奇怪的人,他并不是按照每月每月的这样发工资,他觉得你想什么时候来取都可以,而小明恰好是一个花钱比较大手大脚的人,所以他希望每次取得钱正好够接下来的n个月的花费,以防浪费。

小明很懒,懒到他连钱都尽量不愿多带(只是嫌沉)。但是他在只有m次取钱的机会,所以他想要用m次把n个月的钱都取出来,但想要每次都尽量少取些。给你小明n个月的花费,还有可取的次数m,问小明在保证每次尽量少取些钱的情况下,最多的那次取了多少钱?当然,每次取钱只能取连续几个月的花费。

Input

多组输入。
第一行是两个整数,n(1 ≤ n ≤ 100,000)和m (1 ≤ m ≤ n)

接下来的n行是连续n个月的花费,第i+1行是第i个月的花费。

Output

 输出满足最大的总花费最小的那个组的总花费。

Sample Input

5 3
3
2
9
4
1

Sample Output

9

Hint

 将5个月分为3组,第一组(3,2),第二组(9),第三组(4,1),第二组的总花费最大为9,若按其他的方式分,花费最大的那一组的总花费将>=9.

#include <stdio.h>
#include <stdlib.h>

int N, M;
int n[100005];
int ans;

void binsearch(int low, int high)
{
    if(low > high)//从low到high,情况越来越不理想,所以必须low <= high,当low > high的时候说明最佳答案ans已求出
        return;
    int mid, count = 1, i, sum = 0;//count代表取钱次数,sum代表每次取得钱数
    mid = (high-low) / 2 + low;//二分,设一个low和high的中值mid,代表每次允许取的最大钱数
    for(i = 0; i < N; i++)//求出若每次取得钱数不超过中值mid的条件下需要取几次
    {
        if(sum + n[i] <= mid)//再继续取1月的花费不会超过mid
            sum += n[i];//sum代表某一次取的钱数
        else
        {
            count++;//不能继续再取钱了,要再取一次
            sum = n[i];
        }
    }
    if(count > M)//需要取的次数大于允许取得次数,说明每次允许取的钱数太小了,就确定答案范围一定在mid到high之间
        binsearch(mid+1, high);
    else
    {
        ans = mid;
        binsearch(low, mid-1);//反之就减小每次允许取得钱数
    }
}

int main()
{
    int low, high;//low和high是总花费最小的那个组的总花费的范围
    while(~scanf("%d %d", &N, &M))
    {
        int i;
        low = high = 0;//总花费最小的最理想情况就是,花费最大的那个月单独取1次,其他任意次取的钱数合都比这个月小,此处设low是这个最理想情况的花费。最不理想情况则是只取一次,一次取出所有的花费,此处设low是这个最不理想情况
        for(i = 0; i < N; i++)
        {
            scanf("%d", &n[i]);
            if(n[i] > low)
                low = n[i];//最理想情况
            high += n[i];//最大花费就是只取一次全取完
        }
        binsearch(low, high);//二分的在这个范围内精确答案
        printf("%d\n", ans);
    }
    return 0;
}

上色的纱雾

Time Limit: 1000 ms Memory Limit: 65536 KiB

Submit Statistic Discuss

Problem Description

纱雾画画功力首屈一指,现在她准备上色了,这时候她在想,怎样上色的时间最短呢?

 

3916-1

 

在这里我们把问题简化,平面图抽象成坐标轴,需要上色的地方抽象成 n 个点,纱雾有 m 支画笔。

开始的时候纱雾可以选择让画笔落在坐标轴任意一点上,之后每次移动画笔一个单位的距离都会花费 1 秒(画笔可以左右移动,纱雾强大的能力可以同时移动 m 枝画笔,涂色的时间忽略不计)。现在纱雾想要知道这 n 个点全部上完色最少要多少时间呢?

相信你一定能让可爱的纱雾露出这样的表情的:

 

3916-2

Input

多组输入。

对于每组数据:

  • 首先输入两个以空格分隔的整数 n, m (1 <= n, m <= 10^5),分别表示需要上色的点以及纱雾拥有的画笔的数量
  • 接下来一行是 n 个以空格分隔的整数(绝对值保证不超过 10^9)

Output

对于每组数据,输出一个整数,表示纱雾需要的最少时间(秒)。

Sample Input

3 2
1 4 8
3 1
1 2 9
4 2
1 2 3 6

Sample Output

3
8
2

Hint

两支画笔,第一支画笔初始地点选择 1,第二支画笔初始地点选择地点 8。

那么 3s 后第一支画笔可以到达地点 4,这样 3 个点就可以全部涂上了。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int L, n, m;
int a[100005];
int check(int mid)
{
    int sum=0, count=1;
    for(int i=1; i<n; i++)
    {
        if(sum+a[i]-a[i-1]<=mid)
        {
            sum+=a[i]-a[i-1];
        }
        else
        {
            sum=0;
            count++;
        }
    }
return count<=m;
//    if(count<=m)
//        return 1;
//    else
//        return 0;
}
int main()
{

    while(scanf("%d%d", &n, &m)!=EOF)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
        }
        sort(a, a+n);
        int l=0, r=a[n-1];
        int ans=1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid))
            {
                ans=mid;
                r=mid-1;
            }
            else
                l=mid+1;
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z6q6k6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值