[cogs2482][二分答案]Franky的胡子

【题目描述】
Franky很苦恼他一直不长胡子。
看到同学大叔一样的胡子,Franky总是很无耻的偷笑…
有一天,杨老师要带Franky参加n天的外出培训!!!好开心!!
在火车上,Franky突然发现自己长了胡子!
杨老师带Franky去查了基因图谱==(好贴心)
并且发现:
1.胡子初始每天深夜都会长v cm;
2.每次在剃掉胡子之后胡子增长的速度会增加s cm/天;
Franky很伤心,并且由于来时并不需要剃须刀,所以只能借杨老师的,但是杨老师很吝啬(哼( ﹁ ﹁ ) ~→)
他只允许Franky使用x次剃须刀,而且只允许在晚上睡前用。
【输入格式】
输入格式:
一行,n,s,v,x四个整数。
【输出格式】
输出在培训期间Franky的胡子最长的那天胡子的长度最短值。
【样例输入】
6 1 1 2
【样例输出】
4
【提示】
保证对于20%的数据,x,n,c,s<=10;
对于70%的数据,x,n<=5000,c,s<=100;
对于100%的数据,x,n<=100000,c,s<=10000;

Solution:

经典的二分答案例题

注意到题目要求最大值最小,最大最小是一个典型的二分答案型题目。

所以我们可以二分一个最长的胡子长度,初始我们使R=一个极大值,l=1,mid = (r + l) / 2,然后用模拟的方式运行检验,在运行的过程中如果出现当前胡子长度大于我们二分出的mid我们就需要把当前的胡子剪掉,如果我们n天走下来剪胡子的次数 < x那么对于这个mid值是可行的那么我们让r=mid尝试能不能继续缩小答案,如果>mid那么证明不行我们要扩大答案继续检验,我们不必关心对于一个可行的mid中最长的那个小于mid的情况,因为在二分的过程中我们一定会二分出这个情况。时间复杂度O(nlogm)。

代码如下:

#include 
#define LL long long
using namespace std;
LL n, s, v, x;
bool check(LL len)
{
    LL speed = v, length = 0, ci = x;
    for (LL i = 1; i <= n; i++)
    {
        length += speed;
        if (length > len)
        {
            length = 0;
            speed += s;
            ci--;
            i--;
        }
        if (ci == -1)
            return 0;
    }
    return 1;
}
int main()
{
    freopen("beard.in", "r", stdin);
    freopen("beard.out", "w", stdout);
    cin >> n >> s >> v >> x;
    long long l = 0;
    long long r = n * (s + v);
    while (l <= r)
    {
        LL mid = (l + r) >> 1;
        if (check(mid))
            r = mid - 1;
        else
            l = mid + 1;
    }
    cout << l;
}

你可能感兴趣的:(OI,OI)