uva1401 dp+Trie

这题说的是给了一个长的字符串长度最大300000,又给了4000个单词 单词的长度不超过100.计算这个字符串能组成多少种不同单词的组合,求出方案总数。dp[i]以第i个字符为开始的字符串能有多少种的组成方案,这样每次去比较肯定是会超时的,然后可以用Trie树去优化,这样最多枚举100位种比4000位来得快很多

#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
using namespace std;
const int maxn = 100*4000+10;
const int signma_size =26;
const int mod = 20071027;
struct Trie{
    int ch[maxn][signma_size];
    int val[maxn];
    int sz;
    Trie(){ sz=1; memset(ch[0],0,sizeof(ch[0]));}
    int idx(char c){  return c-‘a‘; }
    void clear(){   sz=1;  memset(ch[0],0,sizeof(ch[0])); }
    void insert(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]==0){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
             }
             u=ch[u][c];
        }
        val[u]=v;
    }
    void find(char *s,int n,vector<int> &va)
    {
          int u=0;
          for(int i=0; i<n; ++i){
               int c=idx(s[i]);
               if(ch[u][c]==0) break;
               u=ch[u][c];
               if(val[u]!=0) va.push_back(val[u]);
          }
    }
}A;
char text[300005],str[4005][105];
int Len[4005],dp[300005];
int main()
{
     int S,cas=0;
     while(scanf("%s%d",text,&S)==2){
         A.clear();
         int n=strlen(text);
         for(int i=1; i<=S; i++){
            scanf("%s",str[i]);
            A.insert(str[i],i);
            Len[i]=strlen(str[i]);
         }
         dp[n]=1;
         vector<int> Val;
         for(int i=n-1; i>=0; i--){

             A.find(text+i,n-i,Val);
             dp[i]=0;
             int L=Val.size();
             for(int j=0; j<L; ++j){
                  int t=Val[j];
                  dp[i]=( dp[i] + dp[ i+Len[ t ] ])%mod;
             }
            Val.clear();
         }
         printf("Case %d: %d\n",++cas,dp[0]);
     }
     return 0;
}

时间: 2024-09-30 22:55:49

uva1401 dp+Trie的相关文章

uva 1401 dp+Trie

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(

Codeforces 633C Spy Syndrome 2(DP+Trie树)

题目大概说给一个加密的字符串,加密规则是把原文转化成小写字母,然后各个单词反转,最后去掉空格.现在给几个已知的单词,还原加密的字符串. 和UVa1401一个道理.. 用dp[i]表示加密字符前i个字符都被解密时,最后所用单词编号,为0表示不能被解密 然后转移一个样,从i出发往前在Trie树上跑,看看能否找到不为0的dp[j],而str[j+1]str[j+2]...str[i-1]str[i]是单词 最后输出方案就根据dp里面的值从最后面回溯找到并输出即可 时间复杂度O(加密字符串长*单词最大长

LA 3942 背单词(dp+Trie)

分析:d[i]=sum{ d(i+len(x) } [i,L]的种类数 可以正向枚举,也可以逆向枚举,Trie+dp的结合题,第一次见,其实dp的思维还是比较简单的 <pre class="cpp" name="code">#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algor

BZOJ 1212: [HNOI2004]L语言( dp + trie )

因为单词很短...用trie然后每次dp暴力查找...用哈希+dp应该也是可以的.... --------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<bitset> using namespace

dp+trie nbut1222 English Game

传送门:点击打开链接 题意:告诉你一个字典,每个单词有一个权值,再给你一个字符串,问这个字符串用字典中的单词不重复字母的覆盖,最大权值是多少.一个单词可以重复出现 思路:先如果不考虑单词匹配,那么就是一个单纯的dp,dp[i]表示前i个已被完全覆盖此时的权值大小,如果在i位置后面有一个单词的长度为l,权值是w,且此时在i位置后长度为l的子字符串就等于那个单词,说明那个单词能放在这个位置,就有dp[l+i]=max(dp[l+i],dp[i]+w) 所以,问题转换为,如何找对应的位置有哪些单词可以

HNU 13108 Just Another Knapsack Problem DP + Trie树优化

题意: 给你一个文本串,和一些模式串,每个模式串都有一个价值,让你选一些模式串来组成文本串,使获得的价值最大.每个模式串不止能用一次. 思路: 多重背包,枚举文本串的每个位置和模式串,把该模式串拼接在当前位置,看下一个位置是否能得到更优值.但是,存在很多模式串不能拼在当前位置的,无效状态.所以可以用Trie树来优化转移. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <c

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 nu

POJ 1625

什么鬼,真的是有负数的吗?我在字符加上了128才过了.dp[i][j],经过i步到达j状态的路径数.转移很容易了,建个trie图就可以,由前一步可连通到和更新即可. 另外,要用到大数和AC自动机DP 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <climits> 6 #include <str

Noip知识点总结

算法思想: 1.模拟 2.搜索    (Search) 枚举(穷举) / 遍历 / 剪枝 / 产生式系统(估价函数)/双向BFS/记忆化搜索 3.查找(字典):折半查找(二分法) / 树形查找(二叉排序树) / Hash 4.递推或归纳 (To 数学方法)  >  递推式  > DP  (ex: 4 Hanoi Tower Problem) 5.分治    (Divided and Conquer)  二分答案 6.贪心    (Greedy) 实现技巧:  循环 递推(顺推/倒推)  >