P8198 背单词的小智

题面

小智在刚刚结束的 CET-4 考试中顺利通过了!现在,他要开始备战 CET-6 了。

可是,他的单词功底太差了,于是他准备开始摆烂背单词。

可是,人脑的能力是有限的,小智的大脑每一天都会有一个记忆的上限,如果超过这个上限,再多的单词也记不下了。

有一天,小智在背单词的时候想到了一个问题,你能帮帮他吗?

小智一共有 n 个单词需要背,第 i 个单词所拥有的「精神值」为 ai

小智每天的记忆力都是有上限 m 的。如果小智在第 i 天内背完了 [l,r] 内的单词,那么这些单词将会占用小智 Ci=j=lraj2 的记忆力。

小智需要在最多 k 天里把这些单词全部背完,他希望你在把这些单词背完的同时,让他每天需要的记忆力的最大值尽可能小。

也就是说,你需要将一个序列最多分为 k 段,请你找到一个最小的 m,使得 1ikCi=j=lraj2m,其中 lr 为各段的左、右端点。

数据规模与约定

对于所有测试点,保证 1n1×1051kn1ai1×106

思路

双倍经验:P1182 数列分段 Section II

思路

这道题明显可以二分答案。

好的,接下来如何写check函数呢?可以贪心,对于每一个数据,能加上就加上,不能加就重新开一个段。

然后就可以在check函数中遍历数组,进行累加。如果累加中有一个地方大于了 k,那么计数器++,并把累加器赋值为当前 ai 的值。最后特判计数器 <k.

代码

记得开long long

#include <algorithm>
#include <iostream>
#define int long long
#define SIZE (int)(1e5+5)
using namespace std;

int n,m,lft=0,rgt=0;
int arr[SIZE];

bool check(int x) {
	int total=0,number=0;
	for(int i=1; i<=n; i++) {
		if(total+arr[i]<=x) {
			total+=arr[i];
		} else {
			total=arr[i];
			number++;
		}
	}
	if(number>=m) {
		return true;
	} else {
		return false;
	}
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		cin>>arr[i];
		arr[i]=arr[i]*arr[i];
		lft = max(lft,arr[i]);
		rgt += arr[i];
	}
	while(lft<=rgt) {
		int mid = (lft+rgt)>>1;
		if(check(mid)) {
			lft=mid+1;
		} else {
			rgt = mid-1;
		}
	}
	cout<<lft;
	return 0;
}
posted @   蒟蒻xiezheyuan  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示