Gym 100273L Language Recognition(Trie+Hash)

来源:互联网 发布:国信金太阳软件手机版 编辑:程序博客网 时间:2024/06/14 06:59

题目地址:http://codeforces.com/gym/100273/attachments

思路:

1.建立Trie,显然所有叶子节点都是等效的,Hash值设为1。

2.对于非叶子节点,需将其儿子Hash值与边对应字母同时考虑。Hash[root]=sigma(Hash[son]*ch+1),Hash[root]*=Son[root],ch为字符,son为root的儿子节点,Son[root]为root的子节点数。

3.对于非叶节点,若其为单词的结尾,Hash[rt]=Hash[rt]*233+111。

4.从叶子节点开始往根走,求出每个点的Hash值,判断有多少非重复值即可。

#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef unsigned long long ULL;const int P=233;const int maxn=150000;set<ULL> s;char st[50];int isw[maxn];int son[maxn];ULL Hash[maxn];int n,vis[maxn][26];int tot,trie[maxn][26];void insert(char *s,int rt){    for(int i=0; s[i]; i++)    {        int x=s[i]-'a';        if(trie[rt][x]==-1)        {            trie[rt][x]=++tot;        }        rt=trie[rt][x];        son[rt]=1;    }    isw[rt]=1;}void pre(int rt){    int flag=0;    for(int i=0; i<26; i++)    {        if(trie[rt][i]!=-1)        {            flag=1;            break;        }    }    if(!flag)    {        Hash[rt]=1;        return ;    }    for(int i=0; i<26; i++)    {        if(trie[rt][i]!=-1&&!vis[rt][i])        {            vis[rt][i]=1;            pre(trie[rt][i]);            son[rt]+=son[trie[rt][i]];        }    }}ULL cal(int P,int x){    ULL mul=1;    for(int i=1;i<=x;i++)    {        mul*=P;    }    return mul;}void solve(int rt){    for(int i=0; i<26; i++)    {        if(trie[rt][i]!=-1&&!vis[rt][i])        {            vis[rt][i]=1;            solve(trie[rt][i]);            Hash[rt]+=Hash[trie[rt][i]]*(i+'a')+1;        }    }    Hash[rt]*=son[rt];    if(isw[rt]) Hash[rt]=Hash[rt]*233+111;    s.insert(Hash[rt]);}int main(){    freopen("language.in","r",stdin);    freopen("language.out","w",stdout);    tot=0;    memset(trie,-1,sizeof(trie));    scanf("%d",&n);    for(int i=0; i<n; i++)    {        scanf("%s",st);        insert(st,0);    }    pre(0);    memset(vis,0,sizeof(vis));    solve(0);    printf("%d\n",s.size());    return 0;}