题目大意
将给定长度为L的字符串S 用字典中单词分解 单词可重复使用 问有多少分解方案数
大体思路
dp[i]表示从i开始的字符串(后缀)的分解方案数 dp[i]=∑dp[i+len(x)] x为字符串S[i...L]的前缀
将单词组成Trie 然后在Trie中查找前缀 找到后递推dp[i]即可
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
using namespace std;
const int maxn=300010;
const int mod=20071027;
char r[maxn];
int dp[maxn];
struct Trie
{
int ch[maxn][26];
int val[maxn];
int sz;
void res(){
sz=1;
memset(ch[0],0,sizeof ch[0]);
memset(val,0,sizeof val);
}
int idx(char c) {
return c-'a';
}
void insert(char *s,int v) {
int u = 0,n=strlen(s);
for(int i = 0; i < n; ++i) {
int c=idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz],0,sizeof ch[sz]);
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=v;
}
void query(char *s,int pos)
{
int u=0,n=strlen(s);
for(int i = 0;i<n;++i) {
int c=idx(s[i]);
if(!ch[u][c]) return ;
u=ch[u][c];
if(val[u]) {
dp[pos]=(dp[pos]+dp[pos+i+1])%mod;
}
}
}
};
Trie trie;
int n;
char temp[105];
int main()
{
// freopen("in.txt","r",stdin);
int Kase=0;
while(~scanf("%s",r)) {
printf("Case %d: ",++Kase);
trie.res();
memset(dp,0,sizeof dp);
int l=strlen(r);
dp[l]=1;
scanf("%d",&n);
for(int i = 0; i < n; ++i) {
scanf("%s",temp);
trie.insert(temp,strlen(temp));
}
for(int i = l-1;i>=0;--i) {
trie.query(r+i,i);
}
printf("%d\n",dp[0]);
}
return 0;
}

本文介绍了一种利用Trie树和动态规划解决字符串分解问题的方法,即计算一个给定长度的字符串可以被字典中单词分解的所有可能方案的数量。
488

被折叠的 条评论
为什么被折叠?



