1. 程式人生 > >清北學堂 清北-Day1-R2-監聽monitor

清北學堂 清北-Day1-R2-監聽monitor

題目描述
【背景】
不閱讀本題的【背景】並不影響通過本題。
三體資訊中沒有包含對三體⼈⽣物形態的任何描述,⼈類要在四百多年以後才能真正看到三體⼈。在閱讀資訊時,葉⽂潔只能把三體⼈想象成⼈類的形象。
1379 號監聽站已經存在了上千年,像這樣的監聽站,在三體世界中有⼏千個,它們全神貫注地聆聽著宇宙間可能存在的智慧⽂明的資訊。最初監聽站中有上百名監聽員,但隨著技術的進步,現在只有⼀個⼈值守了。監聽員是⼀個卑微的職業,他們雖然⾝處恆溫且能保證⽣活供給的監聽室中,在亂世紀不必脫⽔,但他們的⽣命也就在這⼩⼩的空間中流逝,能夠享受到的恆紀元快樂⽐其他⼈要少得多。1379 號監聽員投過⼩⼩的床⼦看著外⾯的三體世界,這是亂紀元的⿊夜,巨⽉還沒有升起來,⼤多數⼈都處於脫⽔的冬眠中,甚⾄植物也本能地脫⽔了,成了附著於地表沒有⽣命的⼀束⼲纖維。星光下,⼤地看上去像⼀⼤塊冰冷的⾦屬。
這是最孤寂的時刻,在靜靜的午夜,宇宙向它的聆聽者展⽰著⼴漠的荒涼。 1379 號監聽員最不願意看的,就是顯⽰器上緩緩移動的那條曲線,那是監聽系統接收到的宇宙電波的波形,⽆意義的噪聲。他感到這條⽆限長的線就是宇宙的抽象,⼀頭連著⽆限的過去,另⼀頭連著⽆限的未來,中間只有為⽆規律⽆⽣命的隨機起伏。⼀個個⾼低錯落的波峰就像⼀粒粒⼤⼩不等的沙⼦,整條線就像是所有沙粒排成⾏形成的⼀維沙漠,荒涼寂寥,長得令⼈⽆法忍受。你可以沿著它向前向後⾛⽆限遠,但永遠找不到歸宿。
【問題描述】
監聽的宇宙電波可以抽象成⼀個長度為 L 的⼩寫字母組成的字串。
同時在三體⼈總結出來了 n 段敏感電波的樣⼦,每段敏感電波的長度都是 m。
現在請你實現⼀個程式,求出在這長度為 L 的⼩寫字母組成的字串中某個敏感電波第⼀次出現的位置(位置從 1 開始計數)。
如果從頭到尾,沒有任何敏感電波出現,輸出”no”(不帶雙引號)。

輸入
第⼀⾏三個整數 L, n, m。
接下來 n ⾏,每⾏⼀個長度為 m 的字串,表⽰敏感電波。
接下來⼀⾏,⼀個長度為 L 的字串,表⽰監聽到的電波。

輸出
輸出⼀個整數或者⼀個字串”no”(不帶雙引號)。

樣例輸入

11 3 3
aba
cba
abc
aaabbabcaba

樣例輸出

6

【樣例輸入 2】

11 3 3
aba
cba
abc 
aaabbabzabz

【樣例輸出 2】

no

對於前 30% 的資料, 1 ≤ L ≤ 100, 1 ≤ n ≤ 100, 1 ≤ m ≤ 20。
對於前 50% 的資料, 1 ≤ L ≤ 10000, 1 ≤ n ≤ 1000, 1 ≤ m ≤ 20。
對於另外 20% 的資料, n = 1。
對於前 100% 的資料, 1 ≤ L ≤ 10^5, 1 ≤ n ≤ 10^4, 1 ≤ m ≤ 20。

本來以為要用KMP,但是看完資料範圍.....emmmm還是算了吧
後來又想到了AC自動機這個嚇人的東西,但是——我不會
於是考慮到NOIP階段常用的字串匹配方法,其實還是hash比較多,但是hash的缺點是隻適用於子串長度相同的情況,否則又要變成 $ \Theta ( n ^ 2 ) $ 了
於是這道題就直接把所有待匹配的串散列出來,然後在主串中列舉長度相等的部分,同取hash值並用二分查詢驗證存在性就好了(當然,要先把散列表排序)
AC程式碼:

#include <algorithm> 
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define ull unsigned long long

const int N = 1e5 + 5;
const int base=233;

int L,n,m;
char s[N],ss[N];
ull h[N];

inline bool check(int l,int r,ull val){
    #define mid ((l+r)>>1)
    while(l<=r){
        if(h[mid]==val) return true;
        if(h[mid]>val) r=mid-1;
        if(h[mid]<val) l=mid+1;
    }
    #undef mid
    return false;
}

int main(){
    scanf("%d%d%d",&L,&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",ss);
        for(int j=0;j<m;++j) h[i]=h[i]*base+ss[j];
    }
    scanf("%s",s+1);std::sort(h+1,h+n+1);
    for(int i=1;i<=L;++i){
        register ull tmp=0;
        for(int j=i;j<m+i;++j) tmp=tmp*base+s[j];
        if(check(1,n,tmp)){printf("%d\n",i);return 0;}
    }
    puts("no");
    return 0;
}