LA-3942(trie树+dp)

时间:2022-03-19 23:58:48

题意:

给出一个由多个不同单词组成的字典,和一个长字符串,把这个字符串分解成若干个单词的连接,问有多少种方法;

思路:

dp[i]表示s[i,L]的方案数,d[i]=∑d[j];s[i,j-1]是一个字典里的单词;

一开始想用mp搞,最后t了;换成了trie树,由于单词的长度不超过100,所以就可以在trie树查找不超过100的长度,把出现单词结点的累加;dp[0]就是答案了;

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
} const LL mod=20071027;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=4e5+10;
const int maxn=500+10;
const double eps=1e-8; //map<string,int>mp;
LL dp[N];
char s[N],str[110];
int sz=0;
int ch[N][28],val[N];
inline void Init()
{
mst(ch,0);
sz=1;
mst(val,0);
}
inline void insert()
{
int u=0,len=strlen(str);
For(i,0,len-1)
{
int temp=str[i]-'a';
if(!ch[u][temp])
{
//mst(ch[sz],0);
val[sz]=0;
ch[u][temp]=sz++;
}
u=ch[u][temp];
}
val[u]=1;
}
inline LL query(int l,int r)
{
LL ans=0;
int u=0;
for(int i=l;r<=r;i++)
{
int temp=s[i]-'a';
if(ch[u][temp])
{
int x=ch[u][temp];
if(val[x])ans=(ans+dp[i+1])%mod;
u=x;
}
else break;
}
return ans;
}
int main()
{
int Case=0;
while(scanf("%s",s)!=EOF)
{
Init();
printf("Case %d: ",++Case);
int q,len=strlen(s);
read(q);
while(q--)
{
scanf("%s",str);
insert();
}
dp[len]=1;
for(int i=len-1;i>=0;i--)
{
dp[i]=0;
int r=min(len-1,i+100);
dp[i]=query(i,r);
}
printf("%lld\n",dp[0]);
} return 0;
}