題目大意
信息是二進制的,共有M條。
約翰已經攔截了這些信息,知道了第i條二進制信息的前b_i位。
他同時知道,奶牛使用N條密碼。
但是,他僅瞭解第j條密碼的前c_j位。
對於每條密碼j,他想知道有多少截得的信息能夠和它匹配。
也就是說,有多少信息和這條密碼有着相同的前綴。
樣例解釋
4條信息,5條密碼
截獲的信息前綴是010,1,100,110。
可能的密碼前綴是0,1,01,01001,11。
0只配對010;
1配對1,100,110;
01只配對010;
01001配對010;
11配對1,110。
題目分析
根據題意:answer=該密碼作爲別的信息前綴+別的信息作爲該密碼前綴的情況。
讓我們分類討論一下(滑稽)
1、該密碼作爲前綴
加入一個變量tr[i].s記錄經過該結點的單詞數量。
即從根節點到這個結點路徑一模一樣。
即有多少個單詞的前綴一樣。
那麼該密碼跑到最後的tr[i].s即爲該密碼作爲別的信息前綴的情況。
2、別的信息作爲該密碼前綴
即跑的時候注意經過所有結點的end相加。
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,len=0;
struct node{int son[10],end,s;}tr[1000010];
void bt(int l)
{
int now=0;
for(int i=1;i<=l;i++)
{
int x; scanf("%d",&x);
if(tr[now].son[x])
{
now=tr[now].son[x];
tr[now].s++;
}
else
{
len++; tr[now].son[x]=len;
now=len; tr[now].end=0;
tr[now].s++;
tr[now].son[0]=tr[now].son[1]=0;
}
}
tr[now].end++;
}
int find(int l)
{
bool gg=false;
int now=0,s=0;
for(int i=1;i<=l;i++)
{
int x; scanf("%d",&x);
if(gg) continue;
if(tr[now].son[x])
{
now=tr[now].son[x];
s+=tr[now].end;//信息作爲該密碼的前綴
}
else gg=true;
//沒有人跟他配了找下去也沒有意義啊
}
if(gg) return s;
return s+(tr[now].s-tr[now].end);
//答案還要加上該密碼作爲別的信息前綴的情況
//如果該密碼與別的信息相同,已經作爲前綴算過一遍了
//所以要 -tr[now].end
//tr[now].s記錄 經過該結點的單詞數量 即從根節點到這個結點路徑一模一樣
//即有多少個單詞的前綴一樣
}
int main()
{
tr[0].son[0]=tr[0].son[1]=0;
scanf("%d%d",&n,&m);
while(n--)
{
int k; scanf("%d",&k);
bt(k);
}
while(m--)
{
int k; scanf("%d",&k);
printf("%d\n",find(k));
}
return 0;
}