[一本通1700]PFS集合

题目描述

有一种特殊的集合叫做PFS(Prefix Free Set)集合。

一个PFS集合由若干字符串构成,且不存在一个字符串是另一个字符串的前缀。空集也被看作是PFS集合。

例如 {\("hello"\)} 和 {\("hello", "goodbye", "giant", "hi"\)} 是PFS集合,但 {\("hello","hell"\)} 和{\("great","gig","g"\)} 不是。

现在给你一个集合,请你求出它的子集是PFS集合的子集个数,答案对\(9191\)取模。

输入

输入数据第一行一个整数\(n\),表示集合里元素的个数。

以下n行,每行一个非空字符串\(s\),仅包含小写英文字母,表示集合中的元素。数据保证不存在两个相同的字符串。

输出

输出一个正整数\(ans\),表示对\(9191\)取模后的答案。

输入样例

3
hello
hi
hell

输出样例

6

提示

输入输出样例解释

除了 {\("hell","hello"\)} 和 {\("hi","hello","hell"\)} 两种情况外,其余情况均是PFS集合。

数据规模

对于\(30%\)的数据,\(n≤20\)
对于\(100%\)的数据,\(1≤n≤50000\),字符串长度不大于\(50\)

思路

\(f[i]+=f[ch[i][1]]\times f[ch[i][2]]\times \cdots\times f[ch[i][26]]\)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 2500000 + 128;

int to[N][26];
int p;

int cnt[N];

int f[N];

void dfs(int u)
{
    int ans = 1;
    for (int i = 0; i < 26; i++)
        if (to[u][i])
        {
            dfs(to[u][i]);
            ans = ans * f[to[u][i]] % 9191;
        }
    f[u] = ans;
    if (cnt[u])
        f[u]++;
}

static char str[50016];

int main()
{
    int n;
    scanf(" %d", &n);
    getchar();

    ++p;
    for (int i = 1; i <= n; i++)
    {
        scanf(" %s", str + 1);
        int len = strlen(str + 1);
        int now = 1;
        for (int i = 1; i <= len; i++)
        {
            if (to[now][str[i] - 'a'] == 0)
                to[now][str[i] - 'a'] = ++p;
            now = to[now][str[i] - 'a'];
        }
        cnt[now] = 1;
    }
    dfs(1);

    printf("%d", f[1] % 9191);
    return 0;
}
posted @ 2021-08-12 08:57  Icys  阅读(167)  评论(0编辑  收藏  举报