UVA-1401 - Remember the Word

刘汝佳新书--训练指南

题意:给出N个不同单词和一个长字符串S。把这个字符串分解成若干个单词的连接(单词尅重复使用),问有多少种方法?

分析:令d[i]表示从字符i开始的字符串的分解方案数,则dans[i]=sum{dans[i+d[x]] | 单词x是S[i...len]的前缀};

// File Name: 1401.cpp
// Author: zlbing
// Created Time: 2013/3/14 18:55:52

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,n) for(int i=0;i<n;i++)
#define REP1(i,n) for(int i=1;i<n+1;i++)
const int maxnode=4000*100+10;
const int sigma_size=26;

// 字母表为全体小写字母的Trie
struct Trie {
  int ch[maxnode][sigma_size];
  int val[maxnode];
  int sz; // 结点总数
  void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } // 初始时只有一个根结点
  int idx(char c) { return c - 'a'; } // 字符c的编号

  // 插入字符串s,附加信息为v。注意v必须非0,因为0代表“本结点不是单词结点”
  void insert(const 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;  // 中间结点的附加信息为0
        ch[u][c] = sz++; // 新建结点
      }
      u = ch[u][c]; // 往下走
    }
    val[u] = v; // 字符串的最后一个字符的附加信息为v
  }
  void find_prefix(char *s,int len,vector<int>& ans){
     // int len=strlen(s);每次找前缀时都算一次长度,要算10^5次,因此导致超时了。。。又这长度是有规律的,因此可以事先算出来
      int u=0;
      for(int i=0;i<len;i++){
          if(s[i]=='\0')break;
        int c=idx(s[i]);
        if(ch[u][c]){
            u=ch[u][c];
            if(val[u])ans.push_back(val[u]);
        }else break;
      }
  }
};
Trie solver;
char str[300050];
int d[4005];
int dans[300050];
const int MOD=20071027;
int main(){
    int cas=0;
    while(~scanf("%s",str)){
        int n;
        scanf("%d",&n);
        solver.clear();
        char word[105];
        REP1(i,n){
            scanf("%s",word);
            int len=strlen(word);
            d[i]=len;
            solver.insert(word,i);
        }
        int len=strlen(str);
        CL(dans,0);
        dans[len]=1;
        for(int i=len-1;i>=0;i--){
            vector<int> ans;
            solver.find_prefix(str+i,len-i,ans);
            for(int j=0;j<ans.size();j++){
                dans[i]=(dans[i]+dans[i+d[ans[j]]])%MOD;
            }
        }
        printf("Case %d: %d\n",++cas,dans[0]);
    }
    return 0;
}

 

posted @ 2013-03-14 20:01  z.arbitrary  阅读(527)  评论(0编辑  收藏  举报