題目地址: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;
}