1. 程式人生 > >Codeforces Round #515 (Div. 3) D. Boxes Packing

Codeforces Round #515 (Div. 3) D. Boxes Packing

  

比賽的時候這題的題意一直沒看懂,後面才明白意思就是有n個物品,然後要求最多可以挑選出多少物品,挑選過程是從第一給物品開始往右邊挑選,對於每一個物品,如果目前的盒子剩餘空間是>=該物品的體積的就直接放進盒子,繼續挑選下一個物品,若目前的盒子剩餘空間是<該物品的體積的,那就要另外開一個盒子來放物品了,若目前已經沒有可用的盒子了,說明這次選取是非法的,那麼之前選取的所有物品都不可以得到,然後就把選取的第一個物品退回去,看是否有剩餘的空間放下該物品,如果還是放不下的話,繼續把第二個拿的物品退回去,直至可以放下該物品為止,然後繼續選取下去,若目前還有可用的盒子,那就繼續選取下去。選取物品的終點是把最後一個物品也選取了,這樣的選取才是合法的,那麼盒子的選取的物品的數量的最大值即是我們要的,這個過程可以看出是依次從第1個至第n個物品開始選取物品,若可以把最後一個也選了,那就更新答案,但是這樣的話複雜度2e5*2e5是會超時的,然後可以發現起點越大挑選成功的可能性越大,具有單調性,因此可以用二分。

#include<bits/stdc++.h>
using namespace std;
#define fuck(x) cout<<#x<<" "<<x<<endl;
const int maxn=2e5+10;
int n,m,k,a[maxn];
bool check(int mid)
{
    int rp=k,num=1;
    for(int i=mid;i<=n;i++)
    {
        if(rp>=a[i])
        {
            rp-=a[i];
        }
        else
            if(num<m)
            {
                num++;
                rp=k-a[i];
            }
            else
                return false;
    }
    return true;
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&(a[i]));
    }
    int low=1,high=n,mid,ans=0;
    while(low<=high)
    {
        mid=(low+high)/2;
        if(check(mid))
        {
            ans=max(ans,n-mid+1);
            high=mid-1;
            //fuck(mid);
        }
        else
            low=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}