[一本通1676]手机游戏 题解

1676:手机游戏



题目描述

明明的手机上有这样一个游戏,一排$n$个怪物,每个怪物的血量是$m_i$。现在明明可以射出$k$个伤害均为$p$的火球,当某个火球射到第$i$个怪物,除了这个怪物会掉血$p$以外,它左边的第$j$个怪物($j≤i$),也会遭到$max(0,p-(i-j)^2)$的溅射伤害。当某个怪物的血量为负的时候,它就死了,但它的尸体依然存在,即其他怪物不会因为它死而改变位置。

明明想用这$k$个火球消灭掉所有的怪物,但他同时希望每个火球的伤害$p$能尽可能的小,这样他才能完美过关。

所有数均为整数。

输入

第一行两个数$n,k$。

第二行$n$个数$m_1,m_2,…,m_n$表示每个怪物的生命值。

输出

一行一个整数表示最小的符合要求的$p$值。

输入样例

3 1
1 4 5

输出样例

6

提示

数据规模

对于30%的数据,$n≤500$。

对于100%的数据,$1≤n≤50000,1≤k≤100000,1≤m_i≤10^9$。

思路

很简单的一道常规二分,虽然有优化方,但我不用
注意要开long long
image

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long ll;

const int N = 5e4 + 12;

int num[N];

ll offset[N]; //怪物受到的伤害

int n, k;

inline bool check(ll p)
{
    int cnt = 0;
    memset(offset, 0, sizeof(offset));
    for (int i = n; i >= 1; i--)
    {
        while (offset[i] <= num[i])
        {
            offset[i] += p;
            cnt++;
            if (cnt > k)
                return false;
            for (ll j = 1; p - j * j > 0 && i - j >= 1; j++)
            {
                offset[i - j] += p - j * j;
            }
        }
    }
    return true;
}

int main()
{
    scanf(" %d %d", &n, &k);
    for (int i = 1; i <= n; i++)
        scanf(" %d", &num[i]);
    ll l = 1, r = 1e18;

    while (l < r)
    {
        ll mid = l + r >> 1;
        if (check(mid))
            r = mid;
        else
            l = mid + 1;
    }
    printf("%d", r);
    return 0;
}
posted @ 2021-08-12 09:37  Icys  阅读(332)  评论(0编辑  收藏  举报