1. 程式人生 > >【洛谷2264】情書(字串水題)

【洛谷2264】情書(字串水題)

點此看題面

大致題意: 給你nn個關鍵詞和一個文字串。讓你求出這些單詞在這個文字串中總共出現次數(一句話中同一單詞只算一次)。

細節

這題其實還是比較水的,一道很簡單的TrieTrie題(資料範圍這麼小,貌似暴力照樣過),居然還能是一道藍題

LinkLink

TrieTrie 詳見部落格 Trie:字典樹

但是,這題還是有很多細節的,大體如下:

  1. 關鍵詞在一句話中的判重
  2. 大小寫須統一(沒看到這個,結果WAWA到心態爆炸)
  3. 判斷一句話是否結束(這也是很重要的,應為題目中說的是一句話中只算一次)。

其餘好像沒什麼問題了。

對於判重以及判斷一句話是否結束

如何判重?

這應該比較簡單,可以用visivis_i來表示一個單詞是否出現過,並在每一句話結束時清空visvis陣列即可。

那麼判斷一句話是否結束呢?

這好像更簡單了,遇到句號就說明一句話結束了。

關於統一大小寫

話說通過這題,我發現了一個十分巧妙的統一大小寫的方法。

已知字元AAASCIIASCII碼為6565,字元aaASCIIASCII碼為9797

仔細觀察這兩個數,不難發現:6597(mod32)65\equiv97(mod\ 32)

3232剛好是252^5,由於22的冪取模的一個性質,因此%32

\%32就等同於&31\&31

因此,對於一個字母,只要將其&31\&31,就可以自動做到大小寫統一,這就非常方便了。

程式碼

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define
swap(x,y) (x^=y,y^=x,x^=y)
#define abs(x) ((x)<0?-(x):(x)) #define INF 1e9 #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD)) #define ten(x) (((x)<<3)+((x)<<1)) #define N 1000 using namespace std; int n; class FIO { private: #define Fsize 100000 #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++) #define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch)) int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize]; public: FIO() {FinNow=FinEnd=Fin;} inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;} inline void read_char(char &x) {while(isspace(x=tc()));} inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;} inline void readln_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,(ch=tc())!='\n') if(!~ch) return;} inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;} inline void write_char(char x) {pc(x);} inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);} inline void end() {fwrite(Fout,1,FoutSize,stdout);} }F; class Class_Trie//字典樹 { private: int rt,tot,cnt,vis[N+5],pos[N+5],Son[N+5][26]; public: inline void Insert(string st)//插入操作 { register int i,x=rt,len=st.length(),nxt; for(i=0;i<len;++i) { if(!Son[x][nxt=st[i]&31]) Son[x][nxt]=++tot; x=Son[x][nxt]; } pos[x]=++cnt;//記錄編號 } inline int Query(string st,int Time)//詢問操作,用Time表示當前是第幾句話 { register int i,x=rt,len=st.length(),nxt; for(i=0;i<len;++i) { if(!Son[x][nxt=st[i]&31]) return 0; x=Son[x][nxt]; } return pos[x]&&vis[pos[x]]^Time?(void)(vis[pos[x]]=Time),1:0;//如果在這句話中沒有出現過該單詞,就返回1,否則返回0 } }Trie; int main() { register int i,len,ans=0,Time=1;register string st,s=""; for(F.read(n),i=1;i<=n;++i) F.read_string(st),Trie.Insert(st);//將關鍵詞插入Trie for(F.readln_string(st),st+=".",len=st.length(),i=0;i<len;++i) { if(isalpha(st[i])||isdigit(st[i])) s+=st[i];//如果是字母或數字,將其儲存 else {ans+=Trie.Query(s,Time),s="";if(st[i]=='.') ++Time;}//否則更新ans,同時判斷這句話是否結束 } return F.write(ans),F.end(),0; }