1、给一个串,在给一个单词集合,求用这个单词集合组成串,共有多少种组法。
例如:串 abcd, 单词集合 a, b, cd, ab
组合方式:2种:
a,b,cd
ab,cd
2、把单词集合建立字典树,然后从后向前dp,dp[i]=dp[i]+dp[i+len(x)]; 其中x为当前找到的前缀长度。
3、
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define MAX 26 #define MOD 20071027 int dp[300005]; struct Trie { Trie *next[MAX]; int v; //根据需要变化,1代表无此单词,-1代表有此单词 }; Trie *root; void createTrie(char *str) { int len = strlen(str); Trie *p = root, *q; for(int i=0; i<len; ++i) { int id = str[i]-'a'; if(p->next[id] == NULL) { // q = (Trie *)malloc(sizeof(Trie)); q = new Trie; q->v = 1; //初始v==1 for(int j=0; j<MAX; ++j) q->next[j] = NULL; p->next[id] = q; } p = p->next[id]; } p->v = -1; //若为结尾,则将v改成-1表示 } int findTrie(char *str,int mI,int len) { int ret=0; //int len = strlen(str);//每次都计算,很浪费时间 Trie *p = root; for(int i=mI; i<len; ++i) { int id = str[i]-'a'; p = p->next[id]; if(p == NULL) //若为空集,表示不存以此为前缀的串 return ret; if(p->v == -1){ //字符集中已有串是此串的前缀 ret=(ret+dp[i+1])%MOD; } } return ret; } int deleteTrie(Trie* T) { int i; if(T==NULL) return 0; for(i=0; i<MAX; i++) { if(T->next[i]!=NULL) deleteTrie(T->next[i]); } //free(T); delete(T); return 0; } int main() { char str[300005]; char str2[105]; int i,S,len,mCase=0; while(~scanf("%s",str)){ root=new Trie; for(i=0; i<MAX; i++) root->next[i]=NULL; memset(dp,0,sizeof(dp)); len=strlen(str); scanf("%d",&S); while(S--){ scanf("%s",str2); createTrie(str2); } dp[len]=1; for(i=len-1;i>=0;--i) dp[i]=findTrie(str,i,len); printf("Case %d: %d\n",++mCase,dp[0]); delete(root); } return 0; }