- 题目1:P8647 [蓝桥杯 2017 省 AB] 分巧克力
思路一:分得巧克力的最小边长为1(题目保证),最大可能为1e5(数据限制)在这个区间内,答案是单调的。原因:若x边长不可行,则大于x的边长都不可行。因此考虑二分答案做法的方向。
思路二:对于最终分边长为x巧克力是否可行的check函数如何写?从“从已知长宽为h[i],w[i]的这些巧克力里去尽量多分边长为x的正方形巧克力”出发,可得贪心写法。每一块巧克力对最终的正方形巧克力的贡献为
sum += (h[i] / x) * (w[i] / x);
check函数顺序枚举所有长方形巧克力即可,sum大于所需值则分边长为x的正方形巧克力是可行方案
综上得出二分答案写法 考虑时间复杂度是否可行
二分复杂度 log(1e5)
check复杂度——n
总——nlog(1e5)
可行 于是二分答案写出代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<cstring>
#include<list>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int MAXN = 1e5 + 10;
int n, k;//巧克力块数 要分的块数
int h[MAXN], w[MAXN];
bool check(int x) {
//验证边长为x的巧克力能否满足块数为k
int sum = 0;
for (int i = 0; i < n; i++) {
sum += (h[i] / x) * (w[i] / x);
}
if (sum >= k)return 1;
else return 0;
}
int main(){
cin >> n >> k;
for (int i = 0; i < n; i++) {
cin >> h[i] >> w[i];
}
int l = 1, r = 1e5;
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) {
//当下边长可行 尝试更大块的巧克力
l = mid + 1;
}
else {
r = mid - 1;
}
}
cout << r;
return 0;
}
- 题目2:[ABC144E] Gluttony
思路一:成绩是队员耗时的最大值,成绩最好,即最大值最小化,联想到二分答案。(单调性:某耗时可行,更长耗时必然可行;,某一耗时不可行,更短耗时必不可行。)
思路二:check函数写法
在不考虑修行情况下,a序列最小值和f序列最大值依次乘积是最优方案。将修行纳入考虑,若一队员耗时 tmp 超过了要求耗时,则将需要的修行记录。需要的修行总和小于k(最多修行时长)则可行。
综上得出二分答案写法:
注意用向下取整实现向上取整的方法
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<cstring>
#include<list>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int MAXN = 2e5 + 10;
ll n, k;//队员数 修行次数
ll a[MAXN], f[MAXN];//消化代价 难吃程度
bool check(ll x) {
ll cnt = 0;
for (int i = 0; i < n; i++) {
ll tmp = a[i] * f[n - i-1];
if (tmp > x) {
//需要修行的次数
cnt += (a[i] * f[n - i - 1] - x + f[n - i - 1] - 1) / f[n - i - 1];
}
}
if (cnt > k)return 0;
return 1;
}
int main(){
cin >> n >> k;
for (int i = 0; i < n; i++) {
cin >> a[i] >> f[i];
}
sort(a, a + n);
sort(f, f + n);
ll l = 0, r = 1e12+10;
while (l <= r) {
ll mid = (l + r) / 2;
if (check(mid)) {
//成绩合理 尝试更好成绩
r = mid - 1;
}
else l = mid + 1;
}
cout << l;
return 0;
}