uva 1401 dp+Trie

来源:互联网 发布:光网络单元 编辑:程序博客网 时间:2024/04/29 12:10
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=4147

题意:给定一个字符串,以及若干单词,求有几种方式能用单词组成字符串 
我先是dp方程推得有问题不知怎么修改搞得卡了很久,然后就是数组开得太小一直RE

trie数组大小=单词个数*单词长度 

dp[i]为以str[i]开头的后缀的ans,dp[i]=segma(dp[k]),其中k表示str[i...k-1]是一个单词,如果k=len,那么dp[i]++;

#include <iostream>#include <cstring>#include <cstdio>using namespace std;#define ll long longconst int N =4000*100+100;const int MOD =20071027;char str[300019],pat[115];ll dp[300019];const int tk=26,tb='a';int top,tree[N][tk+1],len;void init(){    top=1;    memset(tree[0],0,sizeof(tree[0]));}int sear(char*s,int i){    int cnt=0;    ll ans=0;    for(int rt=0;rt=tree[rt][*s-tb] ;++s)    {        if(*(s)==0)break;        cnt++;        if(tree[rt][tk])//cnt!=tree[rt][tk]表示dp[i..len-1]是一个单词,此时没有增加分割的种数        {            if(*(s+1)==0)ans++;            ans=(ans+dp[i+cnt])%MOD;                    //////////////////////        //printf("rt=%d s=%s i=%d cnt=%d dp=%lld\n",rt,str+i+cnt,i,cnt,dp[i]);        //////////////////////        }    }    return ans;}void Insert(char*s, int Rank=0)//Rank为长度{    int rt,nxt;    for(rt=0;*s;rt=nxt,++s,Rank++)    {        nxt=tree[rt][*s-tb];        if(0 == nxt)//nxt!=0的时候就是有公共前缀了,已经在之前做过了,只需继续跳转就行he中插入her,到h,e都是nxt!=0不用插入        {            tree[rt][*s-tb]=nxt=top;            memset(tree[top],0,sizeof(tree[top]));            top++;        }    }    tree[rt][tk]=Rank;}int main(){    //freopen("uva1401.txt","r",stdin);    int n,ncase=1,pos;    while(scanf("%s",str)!=EOF)    {        init();        pos=0;        len=strlen(str);        scanf("%d",&n);        for(int i=0;i<n;i++)        {            scanf("%s",pat);            Insert(pat);        }        dp[len]=0;        for(int i=len-1;i>=0;i--)        {            dp[i]=0;            dp[i]=sear(str+i,i);        }        printf("Case %d: %lld\n",ncase++,dp[0]);    }    return 0;}



2 0