ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

某国颁布了一本 n (n ≤ 10 000) 个单词的词典。单词长
度不超过 40。 
该国的造词法是这样的: 
1: 词典中的单词是一个词。 
2: 能分为两部分的,其中前一部分是一个词典词或者其非
空前缀,后一部分是一个词典词或者其非空后缀的词。 
求能造出的不相同的词汇数目。 

将所有单词建成trie(A),反转后也建一颗trie(B),答案有三种情况

1.原有单词

2.原有单词的 长度>1的 严格前缀,且其最后一个字母是某单词的首字母

3.不是原有单词或其前缀,但可以由前缀和后缀拼出(由于可能重复,对一个由两个单词拼出的串只统计后缀最短的一个,)

分类统计即可

#include<cstdio>
#include<cstring>
typedef long long i64;
const int N=400007;
i64 ans=0;
char ss[10007][43];
int n,ch[N][26],p1=1,p2=1,t0[26],t1[26],t2[26];
int*ed[N];
bool e[N],ee[26];
int main(){
    scanf("%d",&n);
    for(int t=0;t<n;++t){
        scanf("%s",ss[t]);
        int l=strlen(ss[t]),w=1,c;
        for(int i=0;i<l;++i){
            c=ss[t][i]-'a';
            int &u=ch[w][c];
            if(!u)ed[u=++p1]=&u,++t1[c];
            w=u;
        }
        ee[c]=1;
        if(!e[w]){
            if(l>1)--t0[c];
            e[w]=1;
            ++ans;
        }
    }
    for(int i=0;i<26;++i)if(ch[1][i])--t1[i];
    for(int i=0;i<26;++i)if(ee[i])ans+=t0[i]+t1[i];
    for(int i=2;i<=p1;++i)*ed[i]=0;
    for(int t=0;t<n;++t){
        int l=strlen(ss[t]),w=1;
        for(int i=l-1;i>=0;--i){
            int c=ss[t][i]-'a',&u=ch[w][c];
            if(!u)u=++p2,++t2[c];
            w=u;
        }
    }
    ans+=i64(p1-1)*(p2-1);
    for(int i=0;i<26;++i)ans-=i64(t1[i])*t2[i];
    printf("%lld\n",ans);
    return 0;
}

 

posted on 2017-06-14 16:09  nul  阅读(252)  评论(0编辑  收藏  举报