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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值