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