破译密码

Description
大意就是:给n条01信息以及m条01密码,
求对于每条密码,
有多少条信息与他的最长公共前缀=min(密码长度,该条信息长度),
1<=N,M<=50000,其长度均小于等于10000
输入的总长度<=500000
Input
第1行输入N和M
之后N行描述秘密信息,
之后M行描述密码.
每行先输入一个整数表示信息或密码的长度,之后输入这个信息或密码.所有数字之间都用空格隔开.
Output
共M行,输出每条密码的匹配信息数.
Sample Input
4 5  //4条信息,5组密码
3 0 1 0  //第一条信息,长度为3,信息为010
1 1
3 1 0 0
3 1 1 0
1 0  //第一条密码,长度为1,密码为0
1 1
2 0 1
5 0 1 0 0 1
2 1 1
Sample Output
1  //0是010的前缀
3  //1是1,100,110的前缀
1  //01是010的前缀
1  //010是01001的前缀
2  //1是11的前缀,11是110的前缀

sol:先将读入的信息串建立Trie树,本题信息可能是密码的前缀,密码也可能是信息的前缀。难点是怎样判断对于某个串,别人是它的前缀,它又是别人的前缀呢?如:

 

我们对每个点进行标记:

longer[i],记录第i个结点,有多少个单词经过了它,即它被经过了多少次。

shorter[i],记录以第i个结点为结束位置的的单词数。

在进行查找时,依次查找密码的每一个字符,若当前字符不是最后一个字符,则ans+shorter[i](某些信息是该密码的前缀),否则ans+longer[i](该密码查找结束,该密码是信息的前缀)。

 

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define maxn 500500
 6 int n,m,tmp,cnt;
 7 int son[maxn][2],a[10100],longer[maxn],shorter[maxn];
 8   
 9 void insert()
10 {
11     int p=0;
12     for (int i=1;i<=tmp;i++)
13     {
14         if (!son[p][a[i]])
15             son[p][a[i]]=++cnt;
16         p=son[p][a[i]];
17         longer[p]++;
18         //p这个点被经过多少次 
19     }
20     shorter[p]++;
21     //以P为结束端点的单词有多少个 
22 }
23   
24 void work(){
25     int p=0,ans=0;
26     for (int i=1;i<=tmp;i++)
27     {
28         if (!son[p][a[i]])
29             break;
30         if (i<tmp)
31             ans+=shorter[son[p][a[i]]];
32             //如果i<tmp说明当前读的单词还没有走完,此时经过的点
33             //加上其shorter标记,说是这些单词都是他的前缀 
34         else
35             ans+=longer[son[p][a[i]]];
36             //否则说是当前读的单词已走完,此时经过的点被经过了
37             //多少次,就说当前单词是其前缀 
38         p=son[p][a[i]];
39     }
40     printf("%d\n",ans);
41 }
42   
43 int main(){
44     scanf("%d%d",&n,&m);
45     for (int i=1;i<=n;i++)
46     {
47         scanf("%d",&tmp);
48         for (int j=1;j<=tmp;j++)
49              scanf("%d",&a[j]);
50         insert();
51     }
52     for (int i=1;i<=m;i++)
53     {
54         scanf("%d",&tmp);
55         for (int j=1;j<=tmp;j++)
56              scanf("%d",&a[j]);
57         work();
58     }
59     return 0;
60 }

 

posted @ 2020-03-28 22:45  蘑菇JJ  阅读(337)  评论(0编辑  收藏  举报