uva 1519 Dictionary Size

来源:互联网 发布:sql alter 编辑:程序博客网 时间:2024/06/06 08:50

题意:有一个字典,字典有很多单词,要求组合成新词,新词必须来源于原字典,或者由原词的非空前缀和非空后缀组成。

思路:建立trie树,则可以求出不同的前缀和后缀有多少个,但是直接相乘并不是答案,考虑有可能重复的,如XXXAXXX,则A可以选前缀和后缀各一次,XXXA、XXX或者XXX、XXXA,则应该减去。

现在考虑普遍情况,XXXbbb,bbbXXX,若只考虑重复b的情况,假设左边x个b,右边y个b,不考虑重复情况左边应为(1+x)选择,右边应为(1+y)选择,则总共应有这么(1+x)*(1+y)多种情况,但是实际情况应该只有1+x+y种情况,(b的数量,X为任意字符),则应该减去x*y种情况。

还有一个要注意的是如果出现单独的字符,应该标记,建立trie树的时候,不会把单个字符算进去。

#include<cstdio>#include<cstring>#include<algorithm>#define mem(name,value) memset(name,value,sizeof(name))#define FOR(i,n) for(int i=1;i<=n;i++)using namespace std;const int maxn = 400000+5;const int sigma_size = 26;struct Trie{    int ch[maxn][sigma_size];    int cnt[sigma_size];    int sz;    int init(){        mem(ch[0],0); mem(cnt,0);        sz = 1;    }    int idx(char c){return c-'a';}    void insert(const char *s){        int n = strlen(s),u=0;        for(int i=0;i<n;i++){            int c = idx(s[i]);            if(!ch[u][c]){                mem(ch[sz],0);                ch[u][c] = sz++;                if(i) cnt[c]++;            }            u = ch[u][c];        }    }}pre,suf;char s[100];bool vis[26];int main(){    //freopen("in.txt","r",stdin);    int n;    while(scanf("%d",&n)==1){        mem(vis,false);        pre.init(); suf.init();        for(int i=0;i<n;i++){            scanf("%s",s);            if(strlen(s)==1) vis[s[0]-'a']=1;            pre.insert(s);            reverse(s,s+strlen(s));            suf.insert(s);        }        long long ans = (long long)(pre.sz-1)*(suf.sz-1);        for(int i=0;i<sigma_size;i++) ans -= (long long)pre.cnt[i]*suf.cnt[i];        for(int i=0;i<sigma_size;i++) if(vis[i]) ans++;        printf("%lld\n",ans);    }    return 0;}


 

0 0