UVaLive 3942 Remember the Word (dp+字典树)

Remember the Word

DescriptionNeal 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

题意:给你一个长字符串,和一些短字符串,问你用短字符串拼成长字符串的方案数

分析:很明显的dp题。定义状态dp[i]表示从i开始的字符串(后缀)的方案数,则转移方程就是dp[i]+=dp[i+len(x)],x是从i开始的字符串的前缀。

接下来只要求出所有的前缀的长度就行了,枚举肯定会超时,考虑用字典树来做,将短的字符串按字典树建树,单词节点保存单词的长度和是否为单词的标记,每次去查找就行了。

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 26;
const int MOD = 20071027;
typedef struct Trie_Node
{
    bool isWord;
    int len;
    struct Trie_Node *next[MAXN];
}Trie;
int l[110],tot;
void Trie_insert(Trie *root,char *str)
{
    Trie *p=root;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int k=str[i]-‘a‘;
        if(p->next[k]==NULL)
        {
            Trie *t=new Trie;
            for(int j=0;j<MAXN;j++)
                t->next[j]=NULL;
            t->isWord=false;
            p->next[k]=t;
        }
        p=p->next[k];
    }
    p->isWord=true;
    p->len=len;
}
int Trie_search(Trie *root,char *str)
{
    Trie *p=root;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int k=str[i]-‘a‘;
        if(p->next[k]==NULL) return tot;
        if(p->next[k]->isWord)
        {
            tot++;
            l[tot]=p->next[k]->len;
        }
        p=p->next[k];
    }
    return tot;
}
void Trie_del(Trie *root)
{
    for(int i=0;i<MAXN;i++)
    {
        if(root->next[i]!=NULL)
            Trie_del(root->next[i]);
    }
    free(root);
}

char str[300010];
char ss[110];
int dp[3000010];

int main()
{
    int n;
    int iCase=0;
    while(scanf("%s",str)!=EOF)
    {
        iCase++;
        //cout<<str<<endl;
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        Trie *root=new Trie;
        for(int i=0;i<MAXN;i++) root->next[i]=NULL;
        root->isWord=false;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",ss);
            //cout<<ss<<endl;
            Trie_insert(root,ss);
        }
        int len=strlen(str);
        dp[len]=1;
        for(int i=len-1;i>=0;i--)
        {
            tot=0;
            memset(l,0,sizeof(l));
            //cout<<str+i<<endl;
            Trie_search(root,str+i);
            for(int j=1;j<=tot;j++)
            {
                dp[i]+=dp[i+l[j]];
                dp[i]%=MOD;
            }
        }
        printf("Case %d: %d\n",iCase,dp[0]);
        Trie_del(root);
    }
    return 0;
}
时间: 2024-11-10 11:09:35

UVaLive 3942 Remember the Word (dp+字典树)的相关文章

UVALive - 3942 - Remember the Word (Trie树)

UVALive - 3942 Remember the Word Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Neal is very curious about combinatorial problems, and now here comes a problem about words. Knowing that Ray has a p

LA 3942 - Remember the Word (字典树 + dp)

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943 题目大意: 给定一个字符串和给定一个单词集合.问从给定单词集合中选取单词,有多少种选取方法刚好拼接成字符串. 例如: abcd 4 a b cd ab 有两种 a-b-cd ab-cd 这两种情况 解题思路: 因为给定的字符串的长度是3*10^5所以暴力就不能解决问题了

LA 3942 Remember the Word(字典树+DP)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943 题意:一个长字符串和多个短字符串,求短字符串有多少种方式组成长字符串. 状态转移方程: dp[i] = sum(d[i + len(x)])  (x是s[i...L]的前缀) 对于每个i,如果直接暴力寻找s[i...L]的前缀,复杂度为O(nm) (n为短字符

UVALive 3942 Remember the Word 字典树+dp

/** 题目:UVALive 3942 Remember the Word 链接:https://vjudge.net/problem/UVALive-3942 题意:给定一个字符串(长度最多3e5)和m个单词(每个单词长度最多100).单词都是不同的.该字符串可以由若干个单词组成,问最多有多少种组合方式. 思路:字典树+dp 用字典树处理好m个单词,定义dp[i]表示从i开始的字符串可以由单词组成的方式数. 那么dp[i] += dp[i+j]; j表示某个单词和字符串的[i,i+j-1]匹配

UVALive 3942 - Remember the Word(DP,数组Trie+指针Trie)

UVALive 3942 - Remember the Word(DP,数组Trie+指针Trie) ACM 题目地址: UVALive 3942 - Remember the Word 题意: 给一些单词,然后给一个长的单词,问有几种方法能组成这个大单词,单词可以重复用. 分析: DP[i]=sum{DP[j} (i<j<len),从后往前求. 本来用数组Trie写得爽爽的,1A了. 发现2s多,不能忍! 然后用指针Trie写了一遍,各种出错,整个人都不好了... 研究了一遍别人代码,发现快

UVALive - 3942 Remember the Word[Trie DP]

UVALive - 3942 Remember the Word Neal is very curious about combinatorial problems, and now here comes a problem about words. Know- ing that Ray has a photographic memory and this may not trouble him, Neal gives it to Jiejie. Since Jiejie can’t remem

UVALive - 3942 Remember the Word[树状数组]

UVALive - 3942 Remember the Word A potentiometer, or potmeter for short, is an electronic device with a variable electric resistance. It has two terminals and some kind of control mechanism (often a dial, a wheel or a slide) with which the resistance

【暑假】[实用数据结构]UVAlive 3942 Remember the Word

UVAlive 3942 Remember the Word 题目: Remember the Word Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Neal is very curious about combinatorial problems, and now here comes a problem about words. Know

LA、Remember the Word (字典树, 简单dp)

传送门 题意: 给你一个初始串 S,strlen(s) <= 3e5  然后给你 n 个单词. n <= 4000,  每个单词的长度不超过 100 : 问你这个初始串,分割成若干个单词的连接的方案:(这些单词必须是给定的n个单词中的任意一个,一个单词可以被使用多次.) 解: 将 n 个单词建个字典树: dp[ i ] 表示,S的 0 ~ i - 1 切割成若干个 单词的方案数: 枚举S, 枚举到 当前位置 i: 然后就在字典树找,以 S 的 i + 1 开始的, 能不能找到一个单词与之匹配: