板子
int BinarySearch(int a[], int size, int num) {//参数分别为:数组,数组元素的个数,待查找的元素
int left = 1; right = size, mid;
while(left <= right) {
mid = left + (right-left) / 2;
if(num==a[mid]) return mid;//找到了这个数,返回它的下标
else if(num > a[mid]) left = mid + 1;
else right = mid - 1;
}
return -1;//找不到,返回-1
}
PS:这里提一下取区间中点的操作,int mid = (left+right)/2;容易发生整形溢出,所以用int mid = left + (right-left) / 2;
例题1保龄球
题目描述
DL 算缘分算得很烦闷,所以常常到体育馆去打保龄球解闷。因为他保龄球已经打了几十年了,所以技术上不成问题,于是他就想玩点新花招。
DL 的视力真的很不错,竟然能够数清楚在他前方十米左右每个位置的瓶子的数量。他突然发现这是一个炫耀自己好视力的借口——他看清远方瓶子的个数后从某个位置发球,这样就能打倒一定数量的瓶子。
1 OOO
2 OOOO
3 O
4 OO
如上图,每个“O”代表一个瓶子。如果 DL 想要打倒 3 个瓶子就在 1 位置发球,想要打倒 4 个瓶子就在 2 位置发球。
现在他想要打倒 m 个瓶子。他告诉你每个位置的瓶子数,请你给他一个发球位置。
输入格式
输入文件名为 bowling.in。
第一行包含一个正整数 n,表示位置数。
第二行包含 n 个正整数,第 i 个数。表示第 i 个位置的瓶子数,保证各个位置的瓶子数不同。
第三行包含一个正整数 Q,表示 DL 发球的次数。
第四行至文件末尾,每行包含一个正整数 m,表示 DL 需要打倒 m 个瓶子。
输出格式
输出文件名为 bowling.out。
共 Q 行。每行包含一个整数,第 i 行的整数表示 DL 第 i 次的发球位置。若无解,则输出 0。
输入输出样例
输入 #1
5
1 2 4 3 5
2
4
7
输出 #1
3
0
说明/提示
【数据范围】
对于 50%的数据,1 ≤ n,Q ≤ 1000,1 ≤ai,M ≤ 10^5
对于 100%的数据,1 ≤ n,Q ≤ 100000,1 ≤ai,M ≤ 10^9
模板题,就不多解释了,直接上代码
#include<cstdio>
#include<algorithm>
const int N = 1e5 + 50;
using namespace std;
struct node{
int data;
int index;
}a[N];
bool cmp(node x ,node y) {
return x.data < y.data;
}
int main() {
int n, t, x;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i].data);
a[i].index = i;
}
sort(a+1, a+n+1, cmp);
scanf("%d",&t);
for(int i = 1; i <= t; ++i) {
scanf("%d", &x);
int left = 1, right = n, mid;
while(left <= right) {
mid = left + (right-left) / 2;
if(x == a[mid].data) break;
else if(x > a[mid].data) left = mid + 1;
else right = mid - 1;
}
if(x== a[mid].data) {
printf("%d\n",a[mid].index);
}else puts("0");
}
return 0;
}
例题2高考志愿
题目背景
计算机竞赛小组的神牛V神终于结束了万恶的高考,然而作为班长的他还不能闲下来,班主任老t给了他一个艰巨的任务:帮同学找出最合理的大学填报方案。可是v神太忙了,身后还有一群小姑娘等着和他约会,于是他想到了同为计算机竞赛小组的你,请你帮他完成这个艰巨的任务。
题目描述
现有 m(m≤100000) 所学校,每所学校预计分数线是 ai(ai≤1000000)。有 n(n≤100000)位学生,估分分别为 bi(bi≤1000000)。
根据n位学生的估分情况,分别给每位学生推荐一所学校,要求学校的预计分数线和学生的估分相差最小(可高可低,毕竟是估分嘛),这个最小值为不满意度。求所有学生不满意度和的最小值。
输入格式
第一行读入两个整数m,n。m表示学校数,n表示学生数。第二行共有m个数,表示m个学校的预计录取分数。第三行有n个数,表示n个学生的估分成绩。
输出格式
一行,为最小的不满度之和。
输入输出样例
输入 #1
4 3
513 598 567 689
500 600 550
输出 #1
32
说明/提示
数据范围:
对于30%的数据,m,n<=1000,估分和录取线<=10000;
对于100%的数据,n,m<=100,000,录取线<=1000000。
PS:为了更简洁的写出代码,这里介绍一下c++自带的查找函数lower_bound( )和upper_bound( ),附上我 转载 的博客链接 双击进入
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
template<class T>
void read(T &res) {//数据有点多,加了个快读
int f = 1 ;res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar();}
}
int main() {
int m, n, t;
long long sum = 0;
read(m); read(n);
int a[m];
for(int i = 0; i < m; ++i) {
read(a[i]);
}
sort(a, a + m);
for(int i = 0; i < n; ++i) {
read(t);
int x = lower_bound(a, a + m, t) - a;
if(x==0) {//如果全部分数线都大于等于该学生分数
sum += (a[0] - t);
}
else
if(x==m) {//如果全部分数线都小于等于该学生分数。
sum += (t - a[m-1]);
} else {
sum += min(abs(a[x]-t), abs(t-a[x-1]));
}
}
cout<<sum<<"\n";
return 0;
}
分析:需要一点思路,排序之后,找到录取分数线中第一个大于等于该学生分数的分数,取这个分数与学生分数的绝对值,取这个分数前一个分数与学生分数的绝对值,取这两个绝对值中较小值就是该学生的不满意度。然后把所有学生的不满意度加起来就是答案。
PS:班长挺辛(shu)苦(fu)的,能配合工作就别对着干,这(gan)样(de)不(piao)好(liang)
例题3A-B问题
题目描述
出题是一件痛苦的事情!
题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
好吧,题目是这样的:给出一串数以及一个数字 C,要求计算出所有 A-B=C 的数对的个数。(不同位置的数字一样的数对算不同的数对)
输入格式
第一行包括2个非负整数N和C,中间用空格隔开。
第二行有N个整数,中间用空格隔开,作为要求处理的那串数。
输出格式
输出一行,表示该串数中包含的所有满足A−B=C的数对的个数。
输入输出样例
输入 #1
4 1
1 1 2 3
输出 #1
3
说明/提示
对于73%的数据,N≤2000;
对于100%的数据,N≤200000。
所有输入数据都在longint范围内。
2017/4/29新添数据两组
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
long n, c, sum = 0;
cin>>n>>c;
long a[n+1];
for(int i = 0; i < n; ++i) {
cin>>a[i];
}
sort(a , a + n);
for(int i = 0; i < n; ++i) {
sum += (upper_bound(a, a+n, a[i]+c)-a) - (lower_bound(a, a+n, a[i]+c)-a);
}
cout<<sum<<"\n";
return 0;
}
尽管我写出了这题,但是没有如上代码如此简洁明了。流下了不学无术的眼泪
解释一下原理:如果这个数组是有序的,那么对于每一个A的值,在它的后方就只有一个数值B满足A,B的差值为C。
这时我们只需要使用两个函数求出数组中对于每个A,A+C的这两个位置,它们的差即为数组中数值为A+C的元素个数。将这个数加到sum中,完美输出。