zoukankan      html  css  js  c++  java
  • 破译密码

    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
    ",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 }
  • 相关阅读:
    EF实现增删改查
    托管代码与非托管代码的区别
    堆、栈以及队列
    C#装箱和拆箱
    Leecode刷题之旅-C语言/python-349两个数组的交集
    Leecode刷题之旅-C语言/python-344反转字符串
    Leecode刷题之旅-C语言/python-217存在重复元素
    Leecode刷题之旅-C语言/python-206反转链表
    Leecode刷题之旅-C语言/python-204计数质数
    Leecode刷题之旅-C语言/python-203移除链表元素
  • 原文地址:https://www.cnblogs.com/cutepota/p/12590002.html
Copyright © 2011-2022 走看看