UVA1401 Remember the Word 字典树维护dp

题目链接:https://vjudge.net/problem/UVA-1401

题目:

Neal is very curious about combinatorial problems, and now here comes a problem about words. Knowing that Ray has a photographic memory and this may not trouble him, Neal gives it to Jiejie. Since Jiejie can’t remember numbers clearly, he just uses sticks to help himself. Allowing for Jiejie’s only 20071027 sticks, he can only record the remainders of the numbers divided by total amount of sticks. The problem is as follows: a word needs to be divided into small pieces in such a way that each piece is from some given set of words. Given a word and the set of words, Jiejie should calculate the number of ways the given word can be divided, using the words in the set.

Input

The input file contains multiple test cases. For each test case: the first line contains the given word whose length is no more than 300 000.

The second line contains an integer S, 1 ≤ S ≤ 4000. Each of the following S lines contains one word from the set. Each word will be at most 100 characters long. There will be no two identical words and all letters in the words will be lowercase. There is a blank line between consecutive test cases. You should proceed to the end of file.

Output

For each test case, output the number, as described above, from the task description modulo 20071027.

Sample Input

abcd

4

a

b

cd

ab

Sample Output

Case 1: 2

 

题意:
多组输入,首先给你一个长度最大为3e5的字符串s
然后给你一个整数n,后面给你n个长度最大为100的字符串str[i]
问你使用str组成s字符串有多少种方式

这里讲解一下样例:
abcd
4
a
b
cd
ab

那么abcd可以通过a+b+cd 或者 ab+cd 两种方式构成

题解:
dp方程很容易找到
dp[i]=(dp[i]+dp[j]) (i<j)
dp[i]表示构成s字符串的[i,len](这里我们把s字符串下标看作从1开始)这一个子串有多少种方式
那么我们就是需要找到有多少个j可以满足i的需求,因为如果dp[i]+=dp[j],那么s的子串[i,j-1]就需要是str字符串
中的一个才可以

那么暴力判断的话肯定就会TLE,这个时候我们使用字典树来维护
字典树建树的复杂度是O(n),n就是所有字符串的长度,在这里就是所有str字符串的长度,大致建树复杂度就是O(1e5)
另外在字典树上查找满足要求的j的时候,因为str最长为100,所以查找的复杂度最大也是100
那么所有复杂度就是O(1e5)+O(1e5*1e2)

 

代码:

/*
题意:
多组输入,首先给你一个长度最大为3e5的字符串s
然后给你一个整数n,后面给你n个长度最大为100的字符串str[i]
问你使用str组成s字符串有多少种方式

这里讲解一下样例:
abcd
4
a
b
cd
ab

那么abcd可以通过a+b+cd  或者  ab+cd  两种方式构成

题解:
dp方程很容易找到
dp[i]=(dp[i]+dp[j]) (i<j)  
dp[i]表示构成s字符串的[i,len](这里我们把s字符串下标看作从1开始)这一个子串有多少种方式
那么我们就是需要找到有多少个j可以满足i的需求,因为如果dp[i]+=dp[j],那么s的子串[i,j-1]就需要是str字符串
中的一个才可以

那么暴力判断的话肯定就会TLE,这个时候我们使用字典树来维护
字典树建树的复杂度是O(n),n就是所有字符串的长度,在这里就是所有str字符串的长度,大致建树复杂度就是O(1e5)
另外在字典树上查找满足要求的j的时候,因为str最长为100,所以查找的复杂度最大也是100
那么所有复杂度就是O(1e5)+O(1e5*1e2)


*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
const int mod=20071027;
typedef struct Trie* TrieNode;
int dp[maxn],flag;
struct Trie
{
    int sum;
    TrieNode next[30];
    Trie()
    {
        sum=0;
        memset(next,NULL,sizeof(next));
    }
};
void inserts(TrieNode root,char s[105])
{
    TrieNode p = root;
    int len=strlen(s);
    for(int i=0; i<len; ++i)
    {
        int temp=s[i]-'a';
        if(p->next[temp]==NULL) p->next[temp]=new struct Trie();
        p=p->next[temp];
    }
    p->sum+=1;
}
void Del(TrieNode root)
{
    for(int i=0 ; i<2 ; ++i)
    {
        if(root->next[i])Del(root->next[i]);
    }
    delete(root);
}
void query(TrieNode root,char s[105],int pos)
{
    TrieNode p = root;
    int len=strlen(s+1),ci=0;
    for(int i=pos;i<=len;++i)
    {
        int temp=s[i]-'a';
        if(p->next[temp]==NULL)
        {
            return;
        }
        else
        {
            p=p->next[temp];
        }
        ci++;
        if(p->sum>0)
        {
            //printf("%d %d %d\n",pos,dp[pos],dp[pos+ci]);
            dp[pos]+=dp[pos+ci];
            dp[pos]%=mod;
        }
    }
}
char ss[maxn],str[105];
int main()
{
    int n,p=0;
    while(~scanf("%s",ss+1))
    {
        flag=0;
        memset(dp,0,sizeof(dp));
        TrieNode root = new struct Trie();
        scanf("%d",&n);
        for(int i=0 ; i<n; ++i)
        {
            scanf("%s",str);
            inserts(root,str);
        }
        int len=strlen(ss+1);
        dp[len+1]=1;
        for(int i=len;i>=1;--i)
        {
            //printf("------------%d\n",i);
            query(root,ss,i);
        }
        printf("Case %d: %d\n",++p,dp[1]);
        Del(root);
    }
    return 0;
}

 

posted @ 2020-11-14 17:19  kongbursi  阅读(70)  评论(0编辑  收藏  举报