原题链接
算法分析
此题末尾的数据范围很明显告诉我们顺序查找是拿不了满分的,而题目里又保证了输入的麦粒数为升序序列,这时使用二分查找就能很好地提高效率。顺序查找的时间复杂度为O(n),而二分查找的时间复杂度为O(log2n)。所谓二分查找,就是每次取数列正中间的数与要查找的数比较,如果比要查找的数大,就继续在左半边查找,反之则在右半边查找,查找的方法仍像这样,找到这个数就退出循环,因此二分查找又称作折半查找,前提是查找的序列为有序序列。本题则是两次使用二分查找每位顾客所需麦粒的左边界和右边界,最后用
右边界 - 左边界 求出每位顾客的麦粒总数。
示例代码
#include <cstdio>
int n, m, v[1000001], ans[1000001], x, y, l, r, first, last, mid, c = 1;//v数组用来存现有的麦粒,ans数组存答案
int main()
{
scanf ( "%d%d", &n, &m );//输入n和m
for ( int i = 1 ; i <= n ; i++ )
scanf ( "%d", &v[i] );//输入现有麦粒
for ( int i = 1; i <= m; i++ )//n位顾客循环
{
scanf ( "%d%d", &x, &y );//每次输入麦粒范围
l = 0 , r = n , y++; //l为最左边,r为最右边,都是数组下标,为了使没有查到刚好落在y的左边,y需要+1
while ( l <= r )//第一次查找左边界
{
mid = ( l + r ) >> 1;//mid为正中间的数,即(l+r)/2,这是位运算写法
if ( v[mid] < x ) l = mid + 1 , first = mid;//查找右半部分,first为左边界
else r = mid - 1;//查找右半部分
}
l = 0 , r = n;//赋回原来的值
while ( l <= r )//第二次查找右边界
{
mid = ( l + r ) >> 1;//取中值
if ( v[mid] < y ) l = mid + 1 , last = mid;//同理,last为右边界
else r = mid - 1;
}
ans[c++] = last - first;//右边界 - 左边界,答案存进ans数组
}
for ( int i = 1; i < c; i++ )
printf ( "%d\n", ans[i] );//输出答案
return 0;
}