一、复制书稿
题目描述
现在要把 \(m\) 本有顺序的书分给 \(k\) 个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。
现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。
输入格式
第一行两个整数 \(m,k\)。
第二行 \(m\) 个整数,第 \(i\) 个整数表示第 \(i\) 本书的页数。
输出格式
共1行:分配给抄写员的页数的最大值
样例 #1
样例输入 #1
9 3
1 2 3 4 5 6 7 8 9
样例输出 #1
17
提示
\(1\le k \le m \le 500\)。
代码实现
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <algorithm>
#include <cstring>
using namespace std;
int M, K;
int page[505];
//判别答案合法性
bool check(int num){
int group = 1, rest = num;
for(int i = 0; i < M; i++){
//如果这个人当前可以抄的上限页数大于当前这本书书的页数,就交给他抄,不用新增人。
if(rest >= page[i]) rest -= page[i];
//如果这个人抄不了这本书,就要再来一个人,并且更新他的上限页数。
else{
group ++;
rest = num - page[i];
if(rest < 0)
return false;
}
}
//group表示最少需要多少个人
return group <= K;
}
int main(){
cin >> M >> K;
int sum = 0;
int l = 0, r, mid;
for(int i = 0; i < M; i++){
cin >> page[i];
sum += page[i];
}
r = sum;
while(l < r){
mid = (l + r) >> 1;
//如果mid合法,则在左区间寻找答案
if(check(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
二、 青蛙(frog)
题目描述
小 L 向一所小学捐赠了一些青蛙,这些青蛙一共有 \(M\) 种品种,每只青蛙都属于一种品种。
老师需要把所有的青蛙分给 \(N\) 个孩子。每个孩子得到的所有青蛙都必须属于相同的品种,而且可以有一些孩子一只青蛙也没得到。
我们把怄火值定义为得到青蛙最多的孩子得到的青蛙数量。请你帮助老师分青蛙,使得怄火值最小。
例如,如果有 \(4\) 只红品种的青蛙(\(\texttt{RRRR}\))和 \(7\) 个蓝品种的青蛙(\(\texttt{BBBBBBB}\)),要分给 \(5\) 个孩子,
那么我们可以这样划分:\(\texttt{RR}\),\(\texttt{RR}\),\(\texttt{BB}\),\(\texttt{BB}\),\(\texttt{BBB}\)。这样分的怄火值为 \(3\),是最小的。
输入格式
第一行两个正整数,\(N,M\),含义如题目所示。
第二行 \(M\) 个整数,表示第 \(M\) 个品种的青蛙有几只,保证每个品种的青蛙的数量都在 \([1,10^9]\) 中。
输出格式
一行一个整数,表示最小的怄火值。
样例 #1
样例输入 #1
7 4
1 2 3 4
样例输出 #1
2
提示
对于 \(20\%\) 的数据,保证 \(1 \le M \le 10\)。
对于另外 \(30\%\) 的数据,保证 \(1\le M\le 1000\),\(1\le N\le 10000\)。
对于 \(100\%\) 的数据,保证 \(1 \le M \le 3 \times 10^5\),\(1 \le N \le 10^9\),\(M \le N\)。
代码实现
#include <stdio.h>
#include <iostream>
using namespace std;
int a[300005];
int n, m;
bool check(int mid){
int cnt = 0;
for(int i = 1; i <= m; i++){
if(a[i] % mid == 0) cnt += (a[i]/mid);
else cnt += (a[i]/mid+1);
if(cnt > n) return false;
}
return true;
}
int main() {
int maxx = 0;
cin >> n >> m;
for(int i = 1; i <= m; i++){
cin >> a[i];
maxx = max(maxx, a[i]);
}
int l = 1, r = maxx;
while(l < r){
int mid = (l+r) / 2;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << r << endl;
}
三、平均数
题目描述
给一个长度为 \(n\) 的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度 \(\ge m\)。
输入格式
第一行两个整数 \(n\) 和 \(m\)。
接下来 \(n\) 行,每行一个整数 \(a_i\),表示序列第 \(i\) 个数字。
输出格式
一个整数,表示最大平均数的 \(1000\) 倍,如果末尾有小数,直接舍去,不要用四舍五入求整。
样例 #1
样例输入 #1
10 6
6
4
2
10
3
8
5
9
4
1
样例输出 #1
6500
提示
数据规模与约定
- 对于 \(60\%\) 的数据,保证 \(m\le n\le 10^4\);
- 对于 \(100\%\) 的数据,保证 \(1 \leq m\le n\le 10^5\),\(0\le a_i\le2000\)。
代码实现
#include <stdio.h>
#include <iostream>
using namespace std;
long long a[100005], sum[100005];
long long n, m, maxx = 0;
bool check(long long mid){
long long minn = 1e15;
for(int i = 1; i <= n; i++){
sum[i] = sum[i-1] + a[i] - mid;
if(i >= m){
//可能为一个负值
minn = min(minn, sum[i-m]);
if(sum[i] >= minn) return true;
}
}
return false;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
a[i] *= 10000;
if(maxx < a[i]) maxx = a[i];
}
long long l = 0, r = maxx, mid;
while(l < r){
mid = (l+r+1) / 2;
if(check(mid)) l = mid;
else r = mid-1;
}
cout << l / 10 << endl;
return 0;
}
标签:二分,le,int,汇总,mid,long,青蛙,习题,include
From: https://www.cnblogs.com/hsy2093/p/17796564.html