Live2D

CF1066D Boxes Packing(二分答案)

题意描述:
你有$n$个物品,每个物品大小为$a_i$,$m$个盒子,每个盒子的容积为$k$。$Maksim$先生想把物品装入盒子中。对于每个物品,如果能被放入当前的盒子中,则放入当前盒子,否则换一个新的盒子放入。为了放入尽可能多数量的物品,$Maksim$先生会从左开始扔掉一部分物品。现在,$Maksim$先生想知道,他最多能放入盒子多少物品
输入输出格式:
输入格式:
第一行,三个整数$n$,$m$,$k$,$(1≤n,m≤2 \times 10^5$,$ 1≤k≤10^9)$含义参见上文
第二行,$n$ 个数,第$i$表示$a_i$
输出格式:
一行,一个数,表示$Maksim$先生能放入盒子里的最多的物品数量

思路:

水题。。。

因为他挑选的规则一定,而删除的方式一定,所以,答案拥有单调性。

单调性:因为有一个最大合法点,在那之后都是合法的,所以再往后走的话,答案一定越来越小

所以我们的目的就是找这个最大合法点。

怎么找呢?

因为挑选方式一定,所以合法性可以O(n)验证。

这样的话,很显然就可以用一个东西叫二分答案

二分合法点就好了qwq

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rii register int i
#define rij register int j
using namespace std;
int n,m,k;
int a[200005];
bool check(int wz)
{
    int now=0,cnt=1;
    for(rii=wz;i<=n;i++)
    {
        if(a[i]>k)
        {
            return false;
        }
        if(now+a[i]>k)
        {
            now=0;
            cnt++;
        }
        now+=a[i];
    }
    if(cnt>m)
    {
        return false;
    }
    return true;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(rii=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    int l=1,r=n;
    while(l<r)
    {
        if(r-l==1)
        {
            if(check(l)==true)
            {
                break;
            }
            else
            {
                if(check(r)==true)
                {
                    l=r;
                }
                else
                {
                    l=n+1;
                }
                break;
            }
        }
        int mid=(l+r)/2;
        if(check(mid)==true)
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }
    printf("%d",n-l+1);
}

 

posted @ 2018-10-17 22:17  ztz11  阅读(349)  评论(0编辑  收藏  举报