其他分享
首页 > 其他分享> > 1676:手机游戏

1676:手机游戏

作者:互联网

1676:手机游戏


时间限制: 1000 ms         内存限制: 131072 KB
提交数: 864     通过数: 279

【题目描述】

明明的手机上有这样一个游戏,一排$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$。

分析:

由于溅射伤害是一定向左的,且小于直接攻击的伤害。那么当我们需要攻击一个怪物$p$时,直接攻击它一定优于打它右边的(贪心)(前提是它右边的怪物死光了)

那么策略就出来了:二分伤害,判断时从左到右扫一遍,每一次直接攻击并杀死还活着的最右边的怪

code : 

 

 



#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

#define ll long long

int n, k;

long long a[N], b[N];

int read()
{
    int s = 0;
    char ch = getchar();

    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch))
    {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s;
}

int check(ll x)
{
    int p = n;
    int k0 = 0;
    while(p )
    {
        int cnt = a[p] / x;
        ++cnt;
        a[p] = -1;
        k0 += cnt;
        for(int i = p - 1; i ; i--)
        {
            ll damage = max(0ll, x - (p - i) * (p - i));
            if(damage <= 0) break;
            a[i] -= damage * cnt;
        }

        while(a[p] < 0 && p) p--; 

    }
    return k0 <= k;
}

int main()
{
   // scanf("%d %d", &n, &k);
    n = read(), k = read();
    ll L = 0, R = 1e15;
    for(register int i = 1; i <= n; i++)
    {
        a[i] = b[i] = read();
    }
    ll ans = -1;
    while(R - L)
    {
        ll mid = R + L >> 1;
        memcpy(a, b, sizeof b);
        //cout << mid << endl;
        if(check(mid))
        {
            R = mid ;
            ans = mid;
        }
        else L = mid + 1;
    }
    printf("%lld", ans);
    return 0;
}

标签:火球,ch,int,ll,long,手机游戏,怪物,1676
来源: https://www.cnblogs.com/lyc-lb-blogs/p/15141570.html