文章目录
关于二分算法:https://blog.csdn.net/weixin_43772166/article/details/105307762
P2249 【深基13.例1】查找
使用STL即可
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int a[N];
int main(void)
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int t;
while (m--) {
scanf("%d", &t);
int idx;
if (binary_search(a + 1, a + n + 1, t)) {
idx = lower_bound(a + 1, a + n + 1, t) - a;
} else {
idx = -1;
}
printf("%d ", idx);
}
return 0;
}
P1102 A-B 数对
没有想出用二分的做法,用的map,需要开一下longlong
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
map<int, ll> mp;
int main(void)
{
int n, c, t;
cin >> n >> c;
for (int i = 0; i < n; i++) {
scanf("%d", &t);
mp[t]++;
}
ll res = 0;
for (auto item : mp) {
int a = item.first;
res += mp[a] * mp[a - c];
}
cout << res << endl;
return 0;
}
P1873 砍树
check函数可能会爆掉int,所以需要每次都判断是否已经达到了m,如果达到了就返回true。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int n, m, maxv;
int arr[N];
bool check(int h)
{
int sum = 0;
for (int i = 0; i < n; i++) {
if (h < arr[i])
sum += arr[i] - h;
if (sum >= m)
return true;
}
return false;
}
int main(void)
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
maxv = max(maxv, arr[i]);
}
int l = 0, r = maxv;
while (l < r) {
int mid = (l + r + 1) / 2;
if (check(mid))
l = mid;
else
r = mid - 1;
}
cout << r << endl;
return 0;
}
P1024 [NOIP2001 提高组] 一元三次方程求解
判断是否有零点时要写成 < 0 而不是 <= 0,因为当端点是零点时会判断两次
所以可以额外判断区间的左右端点
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
double a, b, c, d;
double get(double x)
{
return a*x*x*x + b*x*x + c*x + d;
}
int main(void)
{
cin >> a >> b >> c >> d;
for (int i = -100; i <= 100; i++) {
double l = i, r = i + 1;
// 判断左端点是否是零点
if (get(l) == 0)
printf("%.2f ", l);
// 如果当前小区间有解,就进行二分
if (get(l) * get(r) < 0) {
while (l + 1e-5 < r) {
double mid = (l + r) / 2;
if (get(l) * get(mid) < 0)
r = mid;
else
l = mid;
}
printf("%.2f ", r);
}
}
return 0;
}
P1678 烦恼的高考志愿
直接使用STL库即可
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int n, m;
int arr[N];
int main(void)
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
sort(arr, arr + n);
int t, res = 0;
while (m--) {
scanf("%d", &t);
int idx = lower_bound(arr, arr + n, t) - arr;
if (idx == 0)
res += abs(arr[0] - t);
else if (idx == n)
res += abs(arr[n - 1] - t);
else
res += min(abs(arr[idx - 1] - t), abs(arr[idx] - t));
}
cout << res << endl;
return 0;
}
P2440 木材加工
常见的木棒分割问题
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int n, m, maxv = 0;
int arr[N];
bool check(int x)
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum += arr[i] / x;
}
return sum >= m;
}
int main(void)
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
maxv = max(maxv, arr[i]);
}
int l = 0, r = maxv;
while (l < r) {
int mid = (l + r + 1) / 2;
if (check(mid))
l = mid;
else
r = mid - 1;
}
cout << r << endl;
return 0;
}
P2678 [NOIP2015 提高组] 跳石头
求最大的最小距离
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int n, m, maxv = 0;
int arr[N];
bool check(int x)
{
int sum = 0, now = 0;
for (int i = 0; i <= n; i++) {
if (arr[i + 1] - now >= x)
now = arr[i + 1];
else
sum++;
}
return sum <= m;
}
int main(void)
{
int L;
cin >> L >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i]);
}
arr[n + 1] = L;
int l = 0, r = L;
while (l < r) {
int mid = (l + r + 1) / 2;
if (check(mid))
l = mid;
else
r = mid - 1;
}
cout << r << endl;
return 0;
}
P3853 [TJOI2007]路标设置
求最小的最大距离
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int n, m;
int arr[N];
bool check(int x)
{
int sum = 0;
for (int i = 0; i < n - 1; i++) {
// 路标之间的距离
int len = arr[i + 1] - arr[i];
if (len > x) {
sum += len / x;
// 如果 len 是 x 的倍数,需要减去一个
if (len % x == 0)
sum--;
}
}
return sum <= m;
}
int main(void)
{
int L;
cin >> L >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int l = 0, r = L;
while (l < r) {
int mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << r << endl;
return 0;
}
做这道题的时候一直有两个样例过不去,在题解后面看到了这样一段话,共勉
(下面这些话,大佬们不要喷,各个地区情况不一样,真的很多人在挣扎)
写这篇题解,真的只是纪念一下,我在计算机的路上经历了很多,去年csp之后正式退役,我受不了一次又一次打击和失败了,很久没有碰计算机,转物理竞赛,疫情期间,闲来无事,写了几个小代码,自动录录屏什么的,突然觉得尽管没得什么奖,但没白学;
我曾经学计算机是无比的功利,一心想拿奖,进队,保送,曾经觉得我放弃计算机是最为错误,现在发现真的没什么对错,计算机的路上已经教了我很多;
如果你正好看到了这篇题解,如果你是挣扎在计算机的道路上,我希望能帮到你,走过的这一路比任何奖项都珍贵,不要太紧张,慢慢走,会好的。
P1182 数列分段 Section II
需要注意的是 sum 应该初始化为1,表示整体是一段
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n, m;
int arr[N];
bool check(int x)
{
// 注意 sum 应该初始化为 1
int sum = 1, now = 0;
for (int i = 0; i < n; i++) {
// 如果当前数字比 x 还大,直接返回false
if (x < arr[i])
return false;
if (now + arr[i] <= x) {
now += arr[i];
} else {
now = arr[i];
sum++;
}
}
return sum <= m;
}
int main(void)
{
cin >> n >> m;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int l = 0, r = 1e9;
while (l < r) {
int mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << r << endl;
return 0;
}
P1163 银行贷款
需要知道每月的变化为剩余金额乘以利率,再减去当月的还款数,即:res * (1 + x/100) - b
如果最后 res > 0 说明税率过高,res < 0说明税率过低
最后上限 r 需要写大一点
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
double a, b, c;
bool check(double x)
{
double res = a;
for (int i = 0; i < c; i++) {
res = res * (1 + x / 100) - b;
}
return res >= 0;
}
int main(void)
{
cin >> a >> b >> c;
double l = 0, r = N;
while (l + 1e-5 < r) {
double mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid;
}
printf("%.1f\n", r);
return 0;
}
P3743 kotori的设备
二分枚举设备可以坚持的时间,计算可以提供的能量和需要的能量
需要注意 r 应该设为1e10
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
double p, a[N], b[N];
bool check(double x)
{
// 可以提供的最多能量
double q = p * x;
// 需要的能量总和
double sum = 0;
for (int i = 0; i < n; i++) {
if (a[i] * x <= b[i])
continue;
else
sum += (a[i] * x - b[i]);
}
return sum <= q;
}
int main(void)
{
double sum = 0;
cin >> n >> p;
for (int i = 0; i < n; i++) {
scanf("%lf%lf", &a[i], &b[i]);
sum += a[i];
}
if (sum <= p) {
puts("-1");
} else {
double l = 0, r = 1e10;
while (l + 1e-5 < r) {
double mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.4f\n", r);
}
return 0;
}