zoukankan      html  css  js  c++  java
  • hdu5384(trie树)

    hdu5384

    给定n个字符串Ai

    给定m个字符串Bi

    问所有的Bi在每个Ai中出现了多少次

    很显然,对Bi建Trie图,然后每次用Ai去匹配的时候,不断查找当前匹配串的最长后缀,这样就能找到答案了

    比赛的时候也这样水过了。(又一次我认为这样不会过,但是交上去却过了)

    如有有这样的数据的话

    1

    1 1

    10^5个a

    10^5个a

    那么时间复杂度是10^10,

    其实上面不断查找当前匹配串的最长后缀是没必要的,是重复操作的。

    如果我们知道当前匹配串的最长后缀包含了多少个Bi,那么就不用去不断回溯了。

    所以我们只要在构建fail指针的时候,处理处当前fail指针指向的字符串包含了多少个Bi,那么就不用不断的回溯了。

    (哈哈,学到东西了)

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <math.h>
     13 using namespace std;
     14 #pragma warning(disable:4996)
     15 #pragma comment(linker, "/STACK:1024000000,1024000000")
     16 typedef long long LL;                   
     17 const int INF = 1<<30;
     18 /*
     19 
     20 */
     21 const int N = 1000000 + 10;
     22 struct Node
     23 {
     24     int fail, next[26];
     25     int cnt;
     26     void init()
     27     {
     28         fail = -1;
     29         cnt = 0;
     30         for (int i = 0; i < 26; ++i)
     31             next[i] = -1;
     32     }
     33 }Trie[N];
     34 int size;
     35 void insert(int root, char *str)
     36 {
     37     int idx, cur = root;
     38     for (int i = 0; str[i]; ++i)
     39     {
     40         idx = str[i] - 'a';
     41         if (Trie[cur].next[idx] == -1)
     42         {
     43             Trie[size].init();
     44             Trie[cur].next[idx] = size++;
     45         }
     46         cur = Trie[cur].next[idx];
     47     }
     48     Trie[cur].cnt++;
     49 }
     50 void makeFail(int root)
     51 {
     52     queue<int> q;
     53     for (int i = 0; i < 26; ++i)
     54     {
     55         if (Trie[root].next[i] == -1)
     56             Trie[root].next[i] = root;
     57         else
     58         {
     59             Trie[Trie[root].next[i]].fail = root;
     60             q.push(Trie[root].next[i]);
     61         }
     62     }
     63     while (!q.empty())
     64     {
     65         int cur = q.front();
     66         q.pop();
     67         for (int i = 0; i < 26; ++i)
     68         {
     69             if (Trie[cur].next[i] == -1)
     70             {
     71                 Trie[cur].next[i] = Trie[Trie[cur].fail].next[i];
     72             }
     73             else
     74             {
     75                 Trie[Trie[cur].next[i]].fail = Trie[Trie[cur].fail].next[i];
     76                 //处理处,当前fail指针指向的字符串包含了多少个Bi
     77                 Trie[Trie[cur].next[i]].cnt += Trie[Trie[Trie[cur].fail].next[i]].cnt;
     78                 q.push(Trie[cur].next[i]);
     79             }
     80 
     81         }
     82     }
     83 }
     84 int match(int root, char *str)
     85 {
     86     int i = 0;
     87     int idx;
     88     int cur = root;
     89     int ret = 0;
     90     while (str[i])
     91     {
     92         idx = str[i] - 'a';
     93         cur = Trie[cur].next[idx];
     94         //int tmp = cur;
     95         //while (tmp != root)
     96         //{
     97         //    ret += Trie[tmp].cnt;
     98         //    tmp = Trie[tmp].fail;
     99         //}
    100         
    101         ret += Trie[cur].cnt;
    102         i++;
    103     }
    104     return ret;
    105 }
    106 /*
    107 题目问所有的Bi在每一个Ai中出现的次数
    108 
    109 一个串的所有子串可以表示为它所有前缀的后缀
    110 对所有的Bi建trie图
    111 我们可以让每个Ai匹配的时候,就让这个当前字符串不断的去寻找最长后缀,
    112 时间复杂度吵了
    113 ,然而数据水,居然过了
    114 */
    115 
    116 char str[666666];
    117 char str2[666666];
    118 int main()
    119 {
    120     int t, n, m;
    121     //freopen("d:/in.txt", "r", stdin);
    122     scanf("%d", &t);
    123     while (t--)
    124     {
    125         scanf("%d%d", &n, &m);
    126         int idx = 0;
    127         size = 1;
    128         Trie[0].init();
    129         Trie[0].fail = 0;
    130         for (int i = 0; i < n; ++i)
    131         {
    132             scanf("%s", str + idx);
    133             idx += strlen(str + idx) + 1;
    134         }
    135         for (int i = 0; i < m; ++i)
    136         {
    137             scanf("%s", str2);
    138             insert(0,str2);
    139         }
    140         makeFail(0);
    141         idx = 0;
    142         for (int i = 0; i < n; ++i)
    143         {
    144             printf("%d
    ", match(0, str + idx));
    145             idx += strlen(str + idx) + 1;
    146         }
    147     }
    148     return 0;
    149 }
    View Code
  • 相关阅读:
    C#操作REDIS例子
    A C# Framework for Interprocess Synchronization and Communication
    UTF8 GBK UTF8 GB2312 之间的区别和关系
    开源项目选型问题
    Mysql命令大全——入门经典
    RAM, SDRAM ,ROM, NAND FLASH, NOR FLASH 详解(引用)
    zabbix邮件报警通过脚本来发送邮件
    centos启动提示unexpected inconsistency RUN fsck MANUALLY
    rm 或者ls 报Argument list too long
    初遇Citymaker (六)
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4728613.html
Copyright © 2011-2022 走看看