【bzoj1590】【Usaco2008 Dec】秘密消息Secret Message
阿新 • • 發佈:2018-10-14
zoj += urn 前綴 usaco class 如果 type getchar
題目描述
貝茜正在領導奶牛們逃跑.為了聯絡,奶牛們互相發送秘密信息. 信息是二進制的,共有M(1≤M≤50000)條.反間諜能力很強的約翰已經部分攔截了這些信息,知道了第i條二進制信息的前bi(l《bi≤10000)位.他同時知道,奶牛使用N(1≤N≤50000)條密碼.但是,他僅僅了解第J條密碼的前cj(1≤cj≤10000)位. 對於每條密碼J,他想知道有多少截得的信息能夠和它匹配.也就是說,有多少信息和這條密碼有著相同的前綴.當然,這個前綴長度必須等於密碼和那條信息長度的較小者. 在輸入文件中,位的總數(即∑Bi+∑Ci)不會超過500000.
輸入
第1行輸入N和M,之後N行描述秘密信息,之後M行描述密碼.每行先輸入一個整數表示信息或密碼的長度,之後輸入這個信息或密碼.所有數字之間都用空格隔開.
輸出
共M行,輸出每條密碼的匹配信息數.
樣例輸入
4 5 3 0 1 0 1 1 3 1 0 0 3 1 1 0 1 0 1 1 2 0 1 5 0 1 0 0 1 2 1 1
樣例輸出
1 3 1 1 2
題解
先把信息建成字典樹。每個信息的結尾打上標記,並記錄以該節點結尾的有多少個。查詢的時候,如果是前綴等於信息的情況,那麽就返回在字典樹上經過的標記的數目,如果是前綴等於密碼的情況,那麽返回密碼的最後一個字符的子樹中的標記數。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=50000*10; int t[maxn][2],n,m,len,root,tot,cnt[maxn],num[maxn]; char c[500000+50]; bool word[maxn]; void insert(char *s,int r){ root=0;int id; for(int i=0;i<r;i++){ id=s[i]-‘0‘; if(!t[root][id]) t[root][id]=++tot; cnt[root]++;root=t[root][id]; } word[root]=true;num[root]++; } int find(char *s,int r){ root=0;int id,ans=0; for(int i=0;i<r;i++){ id=s[i]-‘0‘; if(!t[root][id]){ return ans; } root=t[root][id];if(word[root]) ans+=num[root]; } return ans+cnt[root]; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<‘0‘||cc>‘9‘)&&cc!=‘-‘) cc=getchar(); if(cc==‘-‘) ff=-1,cc=getchar(); while(cc>=‘0‘&&cc<=‘9‘) aa=aa*10+cc-‘0‘,cc=getchar(); aa*=ff; } int main(){ read(m),read(n); for(int i=1;i<=m;i++){ int x,w; read(w);for(int i=1;i<=w;i++) read(x),c[i-1]=x+‘0‘; insert(c,w); } for(int i=1;i<=n;i++){ int x,w; read(w);for(int i=1;i<=w;i++) read(x),c[i-1]=x+‘0‘; printf("%d\n",find(c,w)); } return 0; }
【bzoj1590】【Usaco2008 Dec】秘密消息Secret Message