uvaLive 3942 Remember the Word 字典树

来源:互联网 发布:淘宝美工与运营 编辑:程序博客网 时间:2024/05/21 11:12

题目


题意:

给出一个充满单词的字典,单词长度(<=100),个数(<=4000),再给出一个字符串,长度(<=300 000),问该字符串有多少种拆分单词的方法。


解:

很容想到一维dp,但是类似朴素LIS的转移时间不够,但是这题有个弱点就是单词的长度有限。
本来我想的dp转移是当前状态找前驱状态,不过这样字典树中的字符串需要逆序插入,不方便。所以书上的做法是更新后继状态的那种。


代码:

#include<cstdio>#include<string>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<vector>using namespace std;#define all(x) (x).begin(), (x).end()#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])#define mem(a,x)  memset(a,x,sizeof a)#define ysk(x)  (1<<(x))typedef long long ll;typedef pair<int, int> pii;const int INF =0x3f3f3f3f;const int maxn=4000   ;const int mod=20071027   ;char T[ 300000+10],s[100+10];int n,dp[300000+10],L;struct Trie{    int ch[maxn*100+10][26];    int val[maxn*100+10];    int sz;    void clear()  {  sz=1;mem(ch[0],0);  }    int idx(char c)  {return c-'a';}    void insert(char *s)    {        int x=0;        for(int i=0;s[i];i++)        {            int y=idx(s[i]);            if(!ch[x][y])            {                mem(ch[sz],0);                val[sz]=0;                ch[x][y]=sz++;            }            x=ch[x][y];        }        val[x]=1;    }    void update(int st)    {        int x=0;        for(int i=st;i<=L;i++)        {            int y=idx(T[i]);            if(!ch[x][y]) return;            x=ch[x][y];            if(val[x])  dp[st]=(dp[st]+dp[i+1])%mod;        }    }}trie;void solve(){    L=strlen(T+1);    dp[L+1]=1;    for(int i=L;i>=1;i--)    {        dp[i]=0;        trie.update(i);    }}int main(){   int kase=0;   while(~scanf("%s",T+1))   {       scanf("%d",&n);       trie.clear();       for1(i,n)       {          scanf("%s",s);          trie.insert(s);       }       solve();       printf("Case %d: %d\n",++kase,dp[1]);   }   return 0;}
0 0
原创粉丝点击