搞这个算法刷题系列主要是为了备战蓝桥杯而准备的,目前处于还正在看一些算法基础课程,要先把一些理论知识先给搞懂,然后写题的时候才能有套路的去解。
为什么要写这个系列?
标签:二分
题目描述:
给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。
第二行包含 n 个整数(均在 1∼10000范围内),表示完整数组。
接下来 q 行,每行包含一个整数 k,表示一个询问元素。
输出格式共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1。
数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
示例代码:
#include
#include
using namespace std;
const int N = 100010;
int n, q;
int a[N];
int main()
{
scanf("%d%d", &n, &q);
for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
while(q--)
{
int k;
scanf("%d", &k);
int res1 = -1, res2 = -1;
int l = 0, r = n - 1;
while(l < r)
{
int mid = l + r >> 1;
if(a[mid] >= k) r = mid;
else l = mid + 1;
}
if(a[l] == k) res1 = l;
l = 0, r = n - 1;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(a[mid] <= k) l = mid;
else r = mid - 1;
}
if(a[l] == k) res2 = l;
printf("%d %d\n", res1, res2);
}
return 0;
}
标签:二分
题目描述:
给定一个浮点数 n,求它的三次方根。
输入格式
共一行,包含一个浮点数 n。
输出格式
共一行,包含一个浮点数,表示问题的解。
注意,结果保留 6 位小数。
数据范围
−10000≤n≤10000
输入样例:
1000.00
输出样例:
10.000000
示例代码:
#include
#include
using namespace std;
int main()
{
double n;
cin >> n;
double l = -1e4, r = 1e4, mid;
while(r - l > 1e-8)
{
mid = l + (r - l) / 2;
if(mid * mid * mid > n) r = mid;
else l = mid;
}
printf("%.6f\n", mid);
return 0;
}
标签:二分
题目描述:
机器人正在玩一个古老的基于 DOS 的游戏。
游戏中有 N+1 座建筑——从 0 到 N 编号,从左到右排列。
编号为 0 的建筑高度为 0 个单位,编号为 i 的建筑高度为 H(i) 个单位。
起初,机器人在编号为 0 的建筑处。
每一步,它跳到下一个(右边)建筑。
假设机器人在第 k 个建筑,且它现在的能量值是 E,下一步它将跳到第 k+1 个建筑。
如果 H(k+1)>E,那么机器人就失去 H(k+1)−E 的能量值,否则它将得到 E−H(k+1) 的能量值。
游戏目标是到达第 N 个建筑,在这个过程中能量值不能为负数个单位。
现在的问题是机器人至少以多少能量值开始游戏,才可以保证成功完成游戏?
输入格式
第一行输入整数 N。
第二行是 N 个空格分隔的整数,H(1),H(2),…,H(N) 代表建筑物的高度。
输出格式
输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。
数据范围
1≤N,H(i)≤105,
输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3
示例代码:
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int n;
int h[N];
bool check(int mid)
{
LL res = mid;
for(int i = 1; i <= n; ++i)
{
res = res * 2 - h[i];
if(res > 1e5) return true; //res会爆long long的,所以要加这个判断
if(res < 0) return false;
}
return true;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &h[i]);
int l = 0, r = 1e5;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
return 0;
}
标签:二分
题目描述:
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4 个正整数的平方和。
如果把 0 包括进去,就正好可以表示为 4 个数的平方和。
比如:
5=02+02+12+22
7=12+12+12+22
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4 个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0
示例代码:
#include
#include
#include
#include
using namespace std;
const int N = 5e6+10;
struct Sum
{
int s, a, b;
bool operator<(const Sum& other)
{
if(s != other.s) return s < other.s;
if(a != other.a) return a < other.a;
if(b != other.b) return b < other.b;
}
}sum[N];
int cnt;
int main()
{
int n;
cin >> n;
for(int i = 0; i * i <= n; ++i)
{
for(int j = i; i * i + j * j <= n; ++j)
{
int s = i * i + j * j;
sum[cnt++] = {s,i,j};
}
}
sort(sum,sum+cnt);
//for(int i = 0; i < cnt; ++i) 这样就是按sum的值,而不是a和b的大小了,虽然最后也正确但不是最佳的
for(int i = 0; i * i <= n; ++i) //这样遍历才是按联合主键升序,拿cnt遍历的话,答案也对,不过就不是按联合主键排了,是按sum排
{
for(int j = i; i * i + j * j <= n; ++j)
{
int key = n - i * i - j * j;
int l = 0, r = cnt - 1;
while(l < r)
{
int mid = l + r >> 1;
if(sum[mid].s >= key) r = mid;
else l = mid + 1;
}
if(sum[l].s == key)
{
int c = sum[l].a, d = sum[l].b;
printf("%d %d %d %d\n",i, j, c, d);
return 0;
}
}
}
return 0;
}
标签:二分
题目描述:
儿童节那天有 K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出 K块巧克力分给小朋友们。
切出的巧克力需要满足:
形状是正方形,边长是整数大小相同例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含两个整数 Hi 和 Wi。
输入保证每位小朋友至少能获得一块 1×1 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
数据范围
1≤N,K≤105
,
1≤Hi,Wi≤105
输入样例:
2 10
6 5
5 6
输出样例:
2
示例代码:
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int n, k;
int h[N], w[N];
bool check(int a)
{
LL res = 0;
for(int i = 0; i < n; ++i)
{
res += ((LL)h[i] / a) * (w[i] / a);
if(res >= k) return true; //必须在这里判断一下,不然long long也不够用
}
return false;
}
int main()
{
scanf("%d%d", &n, &k);
for(int i = 0; i < n; ++i) scanf("%d%d", &h[i], &w[i]);
int l = 1, r = 1e5;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n", l);
return 0;
}
if(check()) l = mid
这一行一定是r = mid 或者l = mid,然后才能判断这样是否为l = mid才能+1