1. 程式人生 > >【bzoj1590】【Usaco2008 Dec】秘密消息Secret Message

【bzoj1590】【Usaco2008 Dec】秘密消息Secret Message

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