CodeForces 551C

CodeForces 551C
題意有一個教授要走一條路,但是一條路上堆了很多箱子。這個教授有很多學生,問學生把這條路上的箱子全部搬完需要多長時間。
每個學生在每秒都可以在做出兩個選擇,搬掉一個箱子,向前走一步。
比如第二個樣例。3 2
1 0 2;兩個學生都走到第一堆花費1秒。第一個學生搬掉第一堆的一個箱子,第二個學生向前走一步,花費一秒。
第2個學生向前走一步,花費一秒。搬空第3堆花費2秒。一共5秒。

思路:我們二分枚舉時間t。這裏注意一下這個時間t並不能由枚舉得出,而要通過不斷縮小區間得出。WA了一上午,真菜呀。首先得到
時間t之後,我們看這個時間是否滿足條件。最後一個不爲0的堆總要有人搬空,而且這個最浪費時間。那麼我們就先搬這個。那麼這個
人能搬的盒子數x=t-i(第i堆)。如果這個人能搬空這一堆。就讓他搬前一堆。直到利用完這個人。然後接着再利用下一個人。直到搬空
所有堆爲止。如果我們需要的人數大於給的人數。那麼說明枚舉的這個t比較小。不夠用。如果我們需要的人數<=給的人數。那麼這個t
可能是最小的也可能不是小的t。至於爲啥,想一下樣例3就會明白。所以我們無法知道這個t到底是不是我們要找的t!就會出現可能這個
t就是我們要找的t,但是需要的人數小於給的人數。你說我們是要這個t還是不要呢。(我肯定會要,程序就不知道了(-,-))。所以
只能不斷縮小這個區間。最後枚舉兩個l,r端點來判斷了。代碼如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
ll n,stu,num[100100],tem[100100],flag,top;
int chik(ll tie)
{
    int i;
    ll tm,jud=0,peo=0;
    for(i=1;i<=n;i++)tem[i]=num[i];
    for(i=top;i>=1;i--)//搬空所有箱子,在t時間下,需要多少人。
    {
        if(tem[i])
        {
            tm=tie-i;
            if(tm<=0) return 0;//無法搬最後一堆,時間小
            while(tm>=tem[i]&&i>=1)
            {
                tm-=tem[i];
                tem[i]=0;
                i--;
            }
            peo++;
            if(peo>stu) return 0;//人多了,時間小
            if(tm>0) {tem[i]-=tm;tm=0;}
            i++;
        }
    }
    return peo<=stu;//可能時間多,也可能正好
}
ll ef(ll l,ll r)
{
    ll mid;
    ll ans;
    while(l+1<r)
    {
        mid=(l+r)/2;
        ans=chik(mid);
        if(ans) r=mid;//不能寫成mid+1,因爲你不知道mid是不是答案
        else l=mid;//不能寫成mid-1,同理
    }
    if(chik(r)) printf("%lld\n",r);
    else printf("%lld\n",l);
}
int main()
{
    ll sum=0;
    scanf("%lld%lld",&n,&stu);
    for(int i=1;i<=n;i++)
        {scanf("%lld",&num[i]);sum+=num[i];}
    sum+=n;top=n;
    while(num[top]<=0) top--;
    ef(0,sum);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章