首页 > 其他 > 详细

TJOI2013 单词

时间:2019-10-06 15:41:05      阅读:67      评论:0      收藏:0      [点我收藏+]

题意

给出 \(n\) 个字符串,求出每个字符串在所有字符串中出现的次数。其中 \(n\le200\)\(\sum len \le 10^6\)

洛谷

分析

考试时第一个想到的是Trie树,但通过样例发现 aaa 中单词 a 也算了3次,不会用Trie树处理......

于是想到KMP,把所有的单词都加到字符串 s[] 中,于是样例中的s数组便是这样子的: aaaaaa ,这样子肯定不行,我们要在每个单词后都加一个 # ,所以s数组就成了这样: a#aa#aaa# ,然后就可以愉快的KMP了。

然而此题正解 AC自动机优化成Trie图,kmp实测 \(90pts\) ,洛谷吸氧 \(100pts\)

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1000003
#define il inline
#define re register
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
    T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

int n, len;
int nxt[201][N<<1];
char s[N<<1], ch[201][N];

void pre(int k) {
    for (int i = 2, j = 0; ch[k][i]; ++i) {
        while (j && ch[k][j+1] != ch[k][i]) j = nxt[k][j];
        if (ch[k][j+1] == ch[k][i]) j++;
        nxt[k][i] = j;
    }
}

int kmp(int k) {
    int ans = 0;
    for (int i = 1, j = 0; i <= len; ++i) {
        while (j && ch[k][j+1] != s[i]) j = nxt[k][j];
        if (ch[k][j+1] == s[i]) j++;
        if (j == strlen(ch[k] + 1)) ans++, j = nxt[k][j];
    }
    return ans;
}

int main() {
//  File("word");
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", ch[i] + 1);
        pre(i);
        for (int j = 1; ch[i][j]; ++j) s[++len] = ch[i][j];
        s[++len] = '#';
    }
    for (int i = 1; i <= n; ++i) printf("%d\n", kmp(i));
    return 0;
}

TJOI2013 单词

原文:https://www.cnblogs.com/hlw1/p/11627352.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!