1. 程式人生 > >【題解】T6843 麥粒商店

【題解】T6843 麥粒商店

原題連結

演算法分析

此題末尾的資料範圍很明顯告訴我們順序查詢是拿不了滿分的,而題目裡又保證了輸入的麥粒數為升序序列,這時使用二分查詢就能很好地提高效率。順序查詢的時間複雜度為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;
}