P1918 保龄球
题目描述
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。
输入输出样例
说明
【数据范围】
对于 50%的数据,1 ≤ n,Q ≤ 1000,1 ≤ai,M ≤ 10^5
对于 100%的数据,1 ≤ n,Q ≤ 100000,1 ≤ai,M ≤ 10^9
这道题是经典的二分查找。二分查找有以下几点注意事项:
1.while循环一定要l<=r,不然找到l+1==r的时候,mid=l,如果最后的答案是当前r这个位置的,而while循环里的条件又是l<r,则无法找到正确答案。(即会漏掉一个位置,而且这个位置多半是正确答案)
2.mid可以写为l+(r-l)/2或(l+r)/2.但是要注意特殊情况特殊考虑。有些是需要写成(l+r+1)/2的
3.二分查找一定是要在排序之后才能用,不然l和r无法更新
1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 using namespace std; 8 struct data 9 { 10 int mark,x; 11 bool operator <(const data&o)const 12 { 13 return x<o.x; 14 } 15 }a[101010]; 16 17 int main() 18 { 19 int n; 20 scanf("%d",&n); 21 for(int i=1;i<=n;i++) 22 { 23 scanf("%d",&a[i].x); 24 a[i].mark=i; 25 } 26 sort(a+1,a+1+n); 27 //for(int i=1;i<=n;i++) cout<<a[i].mark<<" "<<a[i].x<<endl; 28 int T; 29 scanf("%d",&T); 30 for(int i=1;i<=T;i++) 31 { 32 int c; 33 scanf("%d",&c); 34 int l=1,r=n; 35 bool ok=false; 36 while(l<=r) 37 { 38 int mid=l+(r-l)/2; 39 if(a[mid].x>c) r=mid-1; 40 else if(a[mid].x<c) l=mid+1; 41 else 42 { 43 ok=1; 44 printf("%d ",a[mid].mark); 45 break; 46 } 47 } 48 if(!ok) printf("0 "); 49 } 50 system("pause"); 51 return 0; 52 }
码一下模板。