1. 程式人生 > >(有坑點)JoyOI1359收入計劃(二分)

(有坑點)JoyOI1359收入計劃(二分)

高考結束後,同學們大都找到了一份臨時工作,渴望掙得一些零用錢。從今天起,Matrix67將連續工作N天(1<=N<=100 000)。每一天末他可以領取當天及前面若干天裡沒有領取的工資,但他總共只有M(1<=M<=N)次領取工資的機會。Matrix67已經知道了在接下來的這N天裡每一天他可以賺多少錢。為了避免自己濫用零花錢,他希望知道如何安排領取工資的時間才能使得領到工資最多的那一次工資數額最小。注意Matrix67必須恰好領工資M次,且需要將所有的工資全部領走(即最後一天末需要領一次工資)。

輸入格式

第一行輸入兩個用空格隔開的正整數N和M
以下N行每行一個不超過10000正整數,依次表示每一天的薪水。

輸出格式

輸出領取到的工資的最大值最小是多少。 提示

【樣例說明】 採取下面的方案可以使每次領到的工資不會多於500。這個答案不能再少了。 100 400 300 100 500 101 400 每一天的薪水 <------1 <-------2 <—3 <—4 <—5 領取工資的時間 500 400 500 101 400 領取到的工資 樣例資料 輸入樣例 #1 輸出樣例 #1

7 5

100

400

300

100

500

101

400

就是一道二分答案題,只是這道題提醒我,有些時候二分的範圍不是可以隨便擴大的!此題的二分答案的下限必須是所有ai 的MAX,上限必須是ai的sum,因為他領的工資必須是由ai組合而成的。

AC Code:

#include<bits/stdc++.h>
#define rg register
#define il inline
#define ll long long
#define rg register
#define maxn 500005
using namespace std;
int a[maxn];
il int read(){rg int x = 0;char ch = getchar();while (ch < '0' || ch > '9') ch = getchar();while (ch >='0' && ch <= '9'){x = (x<<3) + (x<<1) + ch -'0';ch = getchar();}return x;}
bool check(ll mid , int n ,int m){
	ll ans = 0;
	int cnt = 1;
	for (rg int i = 1 ; i <= n ; ++i){
		ans += a[i];
		if (ans > mid) ++cnt , ans = a[i];
	}
	return cnt <= m;
}
int main(){
    rg int n = read() , m = read();
    ll l = 0 , r = 0;
    for (rg int i = 1 ; i <= n ; ++i)
    	a[i] = read() , l = max (l , (ll)a[i]) , r += a[i];
    ll ans = 0;
    while (l <= r){
    	rg ll mid = (l + r) >> 1;
		if (check(mid , n , m)) ans = mid , r = mid - 1;
		else l = mid + 1;	
    }
    cout << ans;
    return 0;	
}