這是湖南科技大學OJ中的一道題目,因爲在刷貼吧的時候看到了,所以就做了。
題目描述
紅魔館最近迎來了兩塊隕石,由於防範不到位,第一塊隕石從天而降,紅魔館爆炸了。館主蕾米莉亞有着強大的力量,她決定阻止第二塊隕石,方法是將隕石打爆,使其分裂成若干個小石塊。
爲了簡化問題,我們可以將一塊隕石看作由連續的 n
個石塊組成,每個石塊包含了一定能量,蕾米莉亞需要毀掉其中某一段連續的石塊(該段能量和爲 s
),被毀掉的石塊將會消失,且因連鎖反應還會使剩餘石塊總能量減少 s
,蕾米莉亞需要保證剩餘石塊總能量不大於 m
,紅魔館就能保存下來。蕾米莉亞想知道她最短需要毀掉的連續石塊長度。
輸入
有多組輸入。
每組輸入第 1
行爲兩個數字 n
、m(1<=n<=10^5,1<=m<=10^9)
,表示總共有 n
個石塊,蕾米莉亞需
要將剩餘總能量控制在不大於 m
。接着 n
行,每行包含一個整數 ai
,表示第i個石塊的能量 (1<=ai<=10^4)
。
各組數據的 n
總和不超過 10^6
。
輸出
每組輸出一行,只包含一個整數,表示最少需要毀掉的連續石塊長度。
題意:找到最少需要毀掉的連續石塊長度。
思路:連續石塊是區間,最少的長度說明要找到的區間和最大且區間最短。存在單調性,連續區間越長,最大的區間和越大。因此,這種題目可以用二分來做,找到第一個滿足題意的區間長度(最短)即可。代碼中用的是二分長度+滑動區間(找到該固定長度的區間中最大的區間和),也可以用前綴和維護區間和,更簡單一點。
代碼:
#include <cstdio>
#include <algorithm>
typedef long long ll;
using namespace std;
const int MAXN = 100100;
ll a[MAXN];
int main() {
ll n, m;
while (~scanf("%lld%lld", &n, &m)) {
ll sum = 0, lo = 0, hi = n;
for (int i = 0; i < n; ++i) {
scanf("%lld", &a[i]);
sum += a[i];
}
while (lo < hi) {
ll mid = (lo + hi) >> 1, maxWindow = 0, nowWindow = 0;
for (int i = 0; i < n; ++i) {
if (i < mid) maxWindow += a[i];
else {
nowWindow = (i == mid) ? maxWindow : nowWindow;
nowWindow = nowWindow + a[i] - a[i - mid]; //當前連續區間的能量
maxWindow = max(nowWindow, maxWindow); //最大能量區間
}
}
if (sum - maxWindow * 2 <= m) hi = mid;
else lo = mid + 1;
}
printf("%lld\n", lo);
}
return 0;
}