UVA_1401_Remerber the Word


给出一个由S个不同单词组成的字典和长字符串。把这个字符串分解成若干个单词的连接(单词可以重复使用),有多少种方法?比如,有4个单词a、b、cd、ab,则abcd有两种分解方法:a+b+cd和ab+cd。

待分解的字符串:长度L不超过300000

单词的个数:1<=S<=4000

思路:令d[i]表示从字符i开始的字符串的分解方案数,则d[i]=sum{d[i+len(x)] | 单词x是S[i..L]的前缀)},由它的递推性质可知,只需要从后往前遍历字符串,记录d[i],再累加就是答案

动态模板:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
#define mod 20071027
int dp[300008],num,re;
struct Trie
{
    Trie *child[26];
    bool end;
    Trie()
    {
        end=0;
       for(int i=0;i<26;++i)
           child[i]=NULL;
    }
};
Trie *root,*s;
void Create(char *str)
{
    s=root;
    int i=0;
    while(str[i])
    {
        if(s->child[str[i]-'a']==0)
        { 
              s->child[str[i]-'a']=new Trie;

        }
        s=s->child[str[i]-'a'];
        i++; //据说++i会更快
    }
    s->end=1;
}
void Search(char *str,int pos)
{
    s=root;
    int i=0;
    while(str[i]!=0&&s->child[str[i]-'a'])      //以后的判断语句能不分开写就不分开了,分开与不分开居然差了几百MS,直接跪倒了我
 
    {
            s=s->child[str[i]-'a'];
            if(s->end==1) //如果遇到是单词结尾的字符
            {

                dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos]; //则num要加上从字符re+i+1开始的串的分解方案数
                if(dp[pos]>=mod) dp[pos]-=mod;
            }
            i++;
     }        
}
char a[300005];
int main()
{
   int n,i,l,t=1;
   char b[105];
   while(~scanf("%s",a))
   {

       scanf("%d",&n);
       root=new Trie;
       for(i=0;i<n;++i)
       {       
          scanf("%s",b);
          Create(b);
       }
       l=strlen(a);
  
       memset(dp,0,sizeof(dp)) ; 
           dp[l]=1;
       for(i=l-1;i>=0;--i)
       {
           Search(a+i,i); //写成Search(&a[i],i)会更快
       }
       printf("Case %d: %d\n",t++,dp[0]);
   }
  return 0;
}

静态模板:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
#define mod 20071027
#define MAXN 400005
int dp[MAXN],num,p;
char a[300005];
struct Trie
{
    int child[26];
    bool end;
    Trie()
    {
      end=0;
      memset(child,0,sizeof(child));
    }
    void set()
    {
        end=0;
        memset(child,0,sizeof(child));
    }
}t[MAXN];
void Create(char *s)
{
    int root=0,i=0,id;
    while(s[i])
    {
        id=s[i]-'a';
        if(t[root].child[id]==0)
            t[root].child[id]=p++;
        root=t[root].child[id];
        i++;
    }
    t[root].end=1;
}
void Search(char *s,int pos)
{
    int root=0,i=0;
    while(s[i]!=0&&t[root].child[s[i]-'a']) //条件判断能合在一起就合在一起,真是各种泪啊,合成一个之后居然可以省几百MS
    {
            root=t[root].child[s[i]-'a'];
            if(t[root].end)
            {
                dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos]; //则num要加上从字符re+i+1开始的串的分解方案数
                if(dp[pos]>=mod) dp[pos]-=mod;
            }
    i++;
    }
}
int main()
{
 int n,i,tt=1;
 char b[200];
  while(~scanf("%s",a))
  {
      scanf("%d",&n);
      p=1;
      memset(dp,0,sizeof(dp));
      for(i=0;i<n;++i)
      {
          scanf("%s",b);
          Create(b);
      }
      int len=strlen(a);  
      memset(dp,0,sizeof(dp)); 
      dp[len]=1; //important
      for(i=len-1;i>=0;--i)
      {
          Search(&a[i],i);
      }
      printf("Case %d: %d\n",tt++,dp[0]);
      for(i=0;i<p;++i) //重新初始化
          t[i].set();
  }
  return 0;
}

一个结构体的静态模板:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
#define mod 20071027
#define MAXN 300005
int dp[MAXN];
char a[MAXN];
struct Trie
{
    int ch[MAXN][26];
    bool val[MAXN];
    int sz;
    void clear()
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
    }
    void Create(char *s)
    {
        int u=0,n=strlen(s);
        for(int i=0;i<n;++i)
        {
            int c=s[i]-'a';
            if(!ch[u][c])
            {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=1;
    }
    void Search(char *s,int pos)
    {
        int i=0,u=0;
        while(s[i]!=0&&ch[u][s[i]-'a'])
        {
            u=ch[u][s[i]-'a'];
            if(val[u])
            {
                dp[pos]=dp[pos+i+1]?dp[pos]+dp[pos+i+1]:dp[pos];
                if(dp[pos]>=mod)
                    dp[pos]-=mod;
            }
            ++i;

        }
    }
}tr;
int main()
{
 int n,i,tt=1;
 char b[200];
  while(~scanf("%s",a))
  {
      scanf("%d",&n);
      tr.clear();
      memset(dp,0,sizeof(dp));
      for(i=0;i<n;++i)
      {
          scanf("%s",b);
          tr.Create(b);
      }
      int len=strlen(a);  
      memset(dp,0,sizeof(dp)); 
      dp[len]=1; //important
      for(i=len-1;i>=0;--i)
      {
          tr.Search(&a[i],i);
      }
      printf("Case %d: %d\n",tt++,dp[0]);
  }
  return 0;
}
优质内容筛选与推荐>>
1、Mineral Invest International MII AB (11.17)
2、android studio Please configure Android SDK / please select Android SDK
3、C# 判断一个数是不是奇数/偶数
4、Asp.net WebPages框架运行原理浅析(转)
5、Linq与Lambda


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn