洛谷 [USACO08DEC]Secret Message G(01字典树)

传送门


解题思路

把每一个信息插入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\n",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 }

 

posted @ 2021-01-10 11:54  尹昱钦  阅读(112)  评论(0编辑  收藏  举报