比赛之字典树题解

这道题第一眼看见题目所给的时间就有一种预感,仅仅是600ms,运行的算法复杂度稍微高一点就会超时。那么我首先是犯傻想偷偷懒,直接是调用一个系统库函数strstr(),希望它能够完成自己的题目,但是显然是超时的。百度了一下它的实现方法是直接采用没有优化的算法,复杂度是最高的。但是由于自己压根就不会写字典树,所以还是抱着一个侥幸的心态去用KMP算法来实现,结果还是铁铁的超时。那么最后的实现应该是通过什么方式呢?

很显然,这道题是一个很裸的字典树题,直接使用字典树的方式解决是最好的。以后也要将这些最基本的算法牢牢地记在心中,不然真的到了比赛的时候就可能要铁铁的后悔了。

题目:

A - Substring Problem

Time Limit:600MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Submit Status

Description

String Matching is an important problem in computer science research and finds applications in Bioinformatics, Data mining,pattern recognition, Internet security and many more areas.

The problem we consider here is a smaller version of it. You are given a string M and N other strings smaller in length than M. You have to find whether each of these N strings is a substring of M. All strings consist of only alphanumeric characters.

You are required to write a C/CPP code to solve the problem.

Input

Input to the program consists of a series of lines. The first line contains the string M (no more than 100000 characters long). The next line contains an integer N (<1000) the number of query strings. Each of the next N lines contain a string S (each of which is no more than2000 characters long).

Output

Output should consist of N lines each with a character ‘Y‘/‘N‘ indicating whether the string S is a substring of String M or not.

Sample Input

Input:
abghABCDE2abABab

Output: 
NY

Note: The test data for this problem not only consist of the official test cases from the contest,as well some cases of my own.

A testcase is added on 25.7.2010,after rejudging 3 users loose accepted.

参考AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1000050 ;
const int sigma_size = 52 ;

int ID[1010] , tot ;
char text[100050] , word[2111] ;
bool flag[1010] ;
int son[maxn][sigma_size] , val[maxn] , f[maxn] , last[maxn] , q[maxn], sz ;

inline int idx(char c) {
    if(c<=‘Z‘) return c - ‘A‘ ;
    else return c - ‘a‘ + 26 ;
}

int Insert(char *s){
    int u = 0 ;
    for(int i=0 ; s[i] ; i++) {
        int v = idx(s[i]) ;
        if(!son[u][v]) son[u][v] = ++sz ;
        u = son[u][v] ;
    }
    if(!val[u]) val[u] = ++tot ;
    return val[u];
}

void get_fail() {
    int rear = 0 ;
    f[0] = 0 ;
    for(int c=0; c<sigma_size ; c++) {
        int u = son[0][c] ;
        if(u) f[u] = last[u] = 0 , q[rear++] = u ;
    }
    for(int _i=0; _i<rear ; _i++) {
        int u = q[_i] ;
        for(int c=0; c<sigma_size; c++){
            int v = son[u][c] ;
            if(!v) { son[u][c] = son[f[u]][c] ; continue ; }
            q[rear++] = v;
            int x = f[u] ;
            while(x && !son[x][c]) x = f[x] ;
            f[v] = son[x][c] ;
            last[v] = val[f[v]] ? f[v] : last[f[v]] ;
        }
    }
}

void print(int u){
    while(u) {
        flag[val[u]] = true ;
        u = last[u] ;
    }
}

void Find(char *s){
    int j = 0;
    for(int i=0; s[i] ; i++) {
        int c=idx(s[i]);
        while(j && !son[j][c]) j = f[j] ;
        j = son[j][c] ;
        print(j) ;
    }
}

int main()
{
    gets(text) ;
    int n ;
    scanf("%d", &n) ; getchar() ;
    for(int i=1; i<=n; i++) {
        scanf("%s" , word) ;
        ID[i] = Insert(word);
    }
    Find(text) ;
    for(int i=1; i<=n; i++) {
        if(flag[ ID[i] ]) puts("Y") ;
        else puts("N") ;
    }
    return 0 ;
}

比赛之字典树题解

时间: 2024-10-13 07:36:05

比赛之字典树题解的相关文章

HDU 4825 Xor Sum(01字典树)题解

思路:先把所有数字存进字典树,然后从最高位贪心. 代码: #include<set> #include<map> #include<stack> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390 看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对. 其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加. 所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值. 这样还会被卡MLE.. 需要分层优化一下. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL l

HDU5269 字典树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5269 ,BestCoder Round #44的B题,关于字典树的应用. 比赛的时候没想出做法,现在补上. 题解: 我们考虑,当lowbit(A xor B) = 2p时,A和B表示的二进制数的后p-1位肯定相同.于是我们可以维护一棵字典树,对于每个数x,可以将其转换为30位的二进制数(不足30位的在前面补0),将该二进制数逆序后插入字典树.统计答案时,对于Ai我们先将其同上述做法转换为30位的二进

HDU 5384 Danganronpa (字典树运用)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5384 题面: Danganronpa Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 512    Accepted Submission(s): 284 Problem Description Danganronpa is a vid

LA_3942 LA_4670 从字典树到AC自动机

首先看第一题,一道DP+字典树的题目,具体中文题意和题解见训练指南209页. 初看这题模型还很难想,看过蓝书提示之后发现,这实际上是一个标准DP题目:通过数组来储存后缀节点的出现次数.也就是用一颗字典树从后往前搜一发.最开始觉得这种搞法怕不是要炸时间,当时算成了O(N*N)毕竟1e5的数据不搞直接上N*N的大暴力...后来发现,字典树根本跑不完N因为题目限制字典树最多右100层左右. 实际上这道题旧思想和模型来说很好(因为直观地想半天还真想不出来..)但是实际实现起来很简单--撸一发字典树就好了

[POJ] #1003# 487-3279 : 桶排序/字典树(Trie树)/快速排序

一. 题目 487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 274040   Accepted: 48891 Description Businesses like to have memorable telephone numbers. One way to make a telephone number memorable is to have it spell a memorable word or

poj 2513 Colored Sticks(欧拉回路 并查集 路径压缩 字典树)(困难)

Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 32545   Accepted: 8585 Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a st

hdu1251 简单字典树

之前去省赛打酱油,遇到一题二进制相关的题目,当时都没做出.后来几个学长找规律打表,然后做:老族长说要用到字典树思想. 也应该学习学习字典树.随手拿水题,看题解,看代码,还是懂了字典树: 内存消耗真的大.. #include<stdio.h> #include<stdlib.h> #include<string.h> #define maxn 26//26个字母 struct trie { trie *next[maxn];//向下26个字母扩展 int v;//记录个数

2014百度之星资格赛—— Xor Sum(01字典树)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起