東方Project題目 1975 紅魔館爆炸了

這是湖南科技大學OJ中的一道題目,因爲在刷貼吧的時候看到了,所以就做了。


題目描述
紅魔館最近迎來了兩塊隕石,由於防範不到位,第一塊隕石從天而降,紅魔館爆炸了。館主蕾米莉亞有着強大的力量,她決定阻止第二塊隕石,方法是將隕石打爆,使其分裂成若干個小石塊。

爲了簡化問題,我們可以將一塊隕石看作由連續的 n 個石塊組成,每個石塊包含了一定能量,蕾米莉亞需要毀掉其中某一段連續的石塊(該段能量和爲 s ),被毀掉的石塊將會消失,且因連鎖反應還會使剩餘石塊總能量減少 s ,蕾米莉亞需要保證剩餘石塊總能量不大於 m ,紅魔館就能保存下來。蕾米莉亞想知道她最短需要毀掉的連續石塊長度。

輸入
有多組輸入。
每組輸入第 1 行爲兩個數字 nm(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章