zcmu-1668: 高橋和低橋

1668: 高橋和低橋

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 38  Solved: 22
[Submit][Status][Web Board]

Description

 有個腦筋急轉彎是這樣的:有距離很近的一高一低兩座橋,兩次洪水之後高橋被淹了兩次,低橋卻只被淹了一次,爲什麼?答案是:因爲低橋太低了,第一次洪水退去之後水位依然在低橋之上,所以不算“淹了兩次”。舉例說明:

假定高橋和低橋的高度分別是5和2,初始水位爲1

第一次洪水:水位提高到6(兩個橋都被淹),退到2(高橋不再被淹,但低橋仍然被淹)

第二次洪水:水位提高到8(高橋又被淹了),退到3。

沒錯,文字遊戲。關鍵在於“又”的含義。如果某次洪水退去之後一座橋仍然被淹,那麼下次洪水來臨水位提高時不能算“又”淹一次。

輸入n座橋的高度以及第i次洪水的漲水水位ai和退水水位bi,統計有多少座橋至少被淹了k次。初始水位爲1,且每次洪水的漲水水位一定大於上次洪水的退水水位。

 

Input

 輸入文件最多包含25組測試數據。每組數據第一行爲三個整數n, m, k(1<=n,m,k<=105)。第二行爲n個整數hi(2<=hi<=108),即各個橋的高度。以下m行每行包含兩個整數ai和bi(1<=bi<ai<=108, ai>bi-1)。輸入文件不超過5MB。

 

Output

 對於每組數據,輸出至少被淹k次的橋的個數。

Sample Input

2 2 22 56 28 35 3 22 3 4 5 65 34 25 2

Sample Output

Case 1: 1Case 2: 3

HINT

Source

第一想到的就是可以轉化成區間覆蓋的問題,把橋的高度按從小到大排序。
然後上一次退潮的點到這次漲潮的點這一段區間就被覆蓋了一次而我們要求的就是有多少個點被覆蓋了k(及以上)次。
第一個想法就是硬搜直接改變他區間的每個值果然直接就超時了。
然後我考慮他的優化問題。我們可以只標記他的開頭和結尾。
如果從第 i 個橋開始被淹    到   第 j 個橋沒有被淹。
那麼   我就用 s[1][ i ] ++  表示從第 i 個橋開始都被淹被淹的次數 + 1
 s[0][ j ]  - -  表示到第 j 個橋開始都沒有被淹 因爲從 i 橋開始都 +1 了 所以從在這點要把那個 1  減去
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int h[20000],w[20000][2],s[2][20000];
int main()
{
    int n,m,x,y,t=1,k,sum;
    while(~scanf("%d %d %d",&n,&m,&k))
    {
        memset(h,0,sizeof(h));
        memset(w,0,sizeof(w));
        memset(s,0,sizeof(s));
        for(int i=0;i<n;i++)scanf("%d",&h[i]);
        sort(h,h+n);
        w[0][0]=1;
        for(int i=0;i<m;i++){
            scanf("%d %d",&w[i][1],&w[i+1][0]);
            w[i+1][0]++;//於是,我將潮落後的高度+1,那麼可以認爲在 [ 低潮,高潮 ] 中的橋都被淹一次
        }
        for(int i=0;i<m;i++){
            int l=lower_bound(h,h+n,w[i][0])-h;//lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一個非遞減序列[first, last)中的第一個大於等於值val的位置。
            int r=upper_bound(h,h+n,w[i][1])-h-1;//upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一個非遞減序列[first, last)中第一個大於val的位置。
            s[1][l]++;
            s[0][r]--;
        }
        int now=0,ans=0;
        for(int i=0;i<n;i++)
        {
            now+=s[1][i];
            if(now>=k)ans++;//大於k說明滿足條件
            now+=s[0][i];
        }
        if(now==k)ans++;
        printf("Case %d: %d\n",t++,ans);
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章