Copying Books UVA - 714

比較經典的一個題目,考察的既不是滑動窗口也不是動態規劃,考察的其實是二分法,二分的範圍是從序列中的最大值到序列的所有的元素之和。每次二分計算出對應的mid值,然後判斷是否能夠將序列劃分成爲不超過k個部分,每個部分的值都不超過mid,如果可以,那麼就繼續縮小範圍,也就是降低下限進行判斷,如果不可以的話,那麼就放大範圍也就是提高下限進行判斷,得出最終的結果之後,就開始對數列進行劃分,這裏要注意一個點,題目要求越靠近前方的部分的和就要越小,所以我們從後向前加‘/’,同時要注意剩餘的斜槓數等於剩下的爲劃分的數字的個數。其他的就比較簡單了,具體實現見如下代碼:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;

int N;
typedef long long LL;
vector<LL> data;
vector<int> ind;

int solve(LL up){
	int ans = 1;
	LL temp = 0;
	for (int i = 0; i < data.size(); i++){
		if (temp + data[i] <= up){
			temp += data[i];
		}
		else{
			ans++;
			temp = data[i];
		}
	}
	return ans;
}

void getRes(LL up,int k){
	LL temp = 0;
	for (int i = data.size() - 1; i >= 0; i--){
		if (temp + data[i] > up || i + 1 < k){
			ind[i] = 1;
			k--;
			temp = data[i];
		}
		else
			temp += data[i];
	}
	for (int i = 0; i < data.size() - 1; i++){
		cout << data[i] << " ";
		if (ind[i]) cout << "/ ";
	}
	cout << data[data.size() - 1] << endl;
}

int main(){
	cin >> N;
	while (N--){
		int m, k;
		cin >> m >> k;
		data.clear();
		ind.clear();
		LL sum = 0;
		LL maxn = -1;
		for (int i = 0; i < m; i++){
			long long t;
			cin >> t;
			data.push_back(t);
			ind.push_back(0);
			sum += t;
			maxn = max(maxn, t);
		}
		LL L = maxn, R = sum;
		while (L < R){
			LL mid = L + (R - L) / 2;
			if (solve(mid) <= k) R = mid;
			else L = mid + 1;
		}
		getRes(L,k);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章