传送门
解题思路
把每一个信息插入01字典树中,用vis[i]表示有多少个信息经过这个点,用vis2[i]表示有多少信息以i这个点结尾。
注意vis中不包含以其结尾的点。
然后对于每一条暗号,跑字典树,经过的点加上vis2[now],结束时加上vis[now],注意当因为匹配不到结束时不能加vis,只有到长度len时加上vis。
感觉说的不是很清楚,看代码吧。
AC代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<iomanip> 5 #include<cmath> 6 using namespace std; 7 const int maxn=500005; 8 int n,m,a[maxn],ch[maxn][3],vis[maxn],cnt=1,len,vis2[maxn]; 9 void insert(int len){ 10 int now=1; 11 for(int i=1;i<=len;i++){ 12 if(!ch[now][a[i]]) ch[now][a[i]]=++cnt; 13 now=ch[now][a[i]]; 14 vis[now]++; 15 } 16 vis2[now]++; 17 vis[now]--;//注意 18 return; 19 } 20 void query(int len){ 21 int now=1,ans=0; 22 for(int i=1;i<=len;i++){ 23 if(ch[now][a[i]]) now=ch[now][a[i]]; 24 else{ 25 ans-=vis[now];//注意 26 break; 27 } 28 ans+=vis2[now]; 29 } 30 ans+=vis[now]; 31 printf("%d ",ans); 32 return; 33 } 34 int main(){ 35 cin>>n>>m; 36 for(int i=1;i<=n;i++){ 37 cin>>len; 38 for(int j=1;j<=len;j++){ 39 scanf("%d",&a[j]); 40 } 41 insert(len); 42 } 43 for(int i=1;i<=m;i++){ 44 cin>>len; 45 for(int j=1;j<=len;j++){ 46 scanf("%d",&a[j]); 47 } 48 query(len); 49 } 50 return 0; 51 }