题目大意:题目链接
给出一个字符串s和若干个单词,统计出有多少种方法把字符串拆分成这些单词。
题目思路:
用 dp [ i ] 表示从s的第i位开始的字符串的分解方案数目。初始化dp [ len + 1 ] = 1,用于末尾的dp[ len ] 状态转移;
我们从字符串的第 i 位出发,一直往后跑字典树;
如果跑到第j位时找到了一个单词,说明从i到j 可以划分成一个单词,加上后缀的j+1的方案数:dp [ i ] + = dp [ j + 1 ];
题目代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define maxn 500005
#define mod 20071027
using namespace std;
char word[maxn];
bool val[maxn];
char str[1005];
int trie[maxn][26];
int dp[maxn];
int tot;
int wlen;
void inserts(char a[])
{
int root=0;
int alen=strlen(a);
for(int i=0;i<alen;++i)
{
int id=a[i]-'a';
if(!trie[root][id])
{
trie[root][id]=++tot;
}
root=trie[root][id];
}
val[root]=true;
//printf("%d---\n",root);
}
int searchs(int x)
{
int sum=0;
int root=0;
for(int i=x;i<=wlen;++i)
{
int id=word[i]-'a';
if(!trie[root][id])//说明根本就没
return sum;
root=trie[root][id];
if(val[root])//找到了一个结点
sum=(sum+dp[i+1])%mod;
}
return sum;
}
int main(void)
{
int n;
int kase=0;
while(~scanf("%s",word+1))
{
tot=0;
wlen=strlen(word+1);
memset(trie,0,sizeof(trie));//忘记清空了
memset(dp,0,sizeof(dp));
memset(val,false,sizeof(val));
//
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str);
inserts(str);
}
dp[wlen+1]=1;
for(int i=wlen;i>=1;i--)
{
dp[i]=searchs(i);
}
printf("Case %d: %d\n",++kase,dp[1]);
}
return 0;
}
呼呼