【UVA1401】Remember the Word Trie+dp

题目大意:给定一个字符串和一个字符串集合,问从集合中选出若干个串组成给定母串的不同方案数。

题解:有些类似于背包问题。状态很好表示,为:\(dp[i]\) 表示母串前 i 个字符的不同方案数,因此,有状态转移方程为:\(dp[i]=\Sigma dp[j],s[j+1...i]=s_0,s_0\in set\) ,可以发现若枚举 \(j < i\) 作为决策集合的话,时间复杂度将是 \(O(n^2)\) 的。优化:可以用 Trie 来直接进行匹配,具体操作如下:将每个集合中的串倒序插入 Trie 中,再对每个 i 进行倒序匹配,若匹配成功则尝试决策转移,时间复杂度为 \(O(n*depth)\),其中 depth 为集合中最长串的长度(小于100)。

代码如下

#include <bits/stdc++.h>
#define cls(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=4e5+10;
const int mod=20071027;

int trie[maxn][26],tot=1;bool ed[maxn];
int kase,n,dp[maxn];
char s[maxn],s2[101];

void insert(int now,int idx){
    if(!idx){ed[now]=1;return;}
    int ch=s2[idx]-‘a‘;
    if(!trie[now][ch])trie[now][ch]=++tot;
    now=trie[now][ch],insert(now,idx-1);
}

void go(int now,int idx,int i){
    if(ed[now])dp[i]=((long long)dp[i]+dp[idx])%mod;
    if(!idx)return;
    else if(!trie[now][s[idx]-‘a‘])return;
    else go(trie[now][s[idx]-‘a‘],idx-1,i);
}

void read_and_parse(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%s",s2+1),insert(1,strlen(s2+1));
}

void solve(){
    dp[0]=1;
    for(int i=1;i<=strlen(s+1);i++)go(1,i,i);
    printf("Case %d: %d\n",++kase,dp[strlen(s+1)]);
}

void init(){
    cls(trie,0),cls(ed,0),cls(dp,0),tot=1;
}

int main(){
    while(scanf("%s",s+1)!=EOF){
        init();
        read_and_parse();
        solve();
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10140852.html

时间: 2024-10-12 03:56:15

【UVA1401】Remember the Word Trie+dp的相关文章

【CF827F】Dirty Arkady&#39;s Kitchen DP

[CF827F]Dirty Arkady's Kitchen 题意:给你一张n个点,m条边的有向图,每条边长度为1,第i条边在[li,ri)的时间内可以进入,求1到n的最短路. $n,m\le 5\times 10^5$ 题解:我们先将所有边按l从小到大排序,然后依次向图中加入每条边.首先对于一条边,我们可以反复走这条边,因此不难想到将每个点按到达时间的奇偶性拆成两个.然后每个点可以到达的时间就可以看成若干个互不相交的区间,我们用mn[i],mx[i]维护当前最后一段区间的左右端点. 在加入一条

【CF706D】Vasiliy&#39;s Multiset Trie+贪心

题目大意:需要维护一种数据结构,支持以下三种操作:插入一个数,删除一个数,查询该数据结构中的数异或给定数的最大值. 题解:如果没有删除操作就是一个标准的 Trie 上贪心求最大异或和问题.现在需要支持删除操作,因此,在树上每个节点维护一个额外的标记,表示有多少个数的某一位经过当前节点.插入操作依然只需修改树上一条链,而删除一个数时,同样需要将这条链上的标记值减 1 即可.这时便可以根据经过的每个点标记值是否为 0 进行贪心操作. 代码如下 #include <bits/stdc++.h> us

UOJ #2. 【NOI2014】起床困难综合症 数位DP

第二次做NOI的题... .预处理+数位DP #2. [NOI2014]起床困难综合症 id=2" style="">统计提交情况 id=2#tab-statement" style="color:rgb(85,85,85); text-decoration:none; position:relative; display:block; padding:10px 15px; margin-right:2px; line-height:1.428571

【BZOJ2314】士兵的放置 树形DP

[BZOJ2314]士兵的放置 Description 八中有N个房间和N-1双向通道,任意两个房间均可到达.现在出了一件极BT的事,就是八中开始闹鬼了.老大决定加强安保,现在如果在某个房间中放一个士兵,则这个房间以及所有与这个房间相连的房间都会被控制.现在 老大想知道至少要多少士兵可以控制所有房间.以及有多少种不同的方案数. Input 第一行一个数字N,代表有N个房间,房间编号从1开始到N.N<=500000,下面将有N-1行,每行两个数,代表这两个房间相连. Output 第一行输出至少有

【BZOJ3679】数字之积 DFS+DP

[BZOJ3679]数字之积 Description 一个数x各个数位上的数之积记为f(x) <不含前导零>求[L,R)中满足0<f(x)<=n的数的个数 Input 第一行一个数n第二行两个数L.R Output 一个数,即满足条件的数的个数 Sample Input 5 19 22 Sample Output 1 HINT 100%     0<L<R<10^18 , n<=10^9 题解:真心喜欢这种搜索+DP的题~ 先预处理出f(x)所有可能的取值,

【BZOJ3769】spoj 8549 BST again DP(记忆化搜索?)

[BZOJ3769]spoj 8549 BST again Description 求有多少棵大小为n的深度为h的二叉树.(树根深度为0:左右子树有别:答案对1000000007取模) Input 第一行一个整数T,表示数据组数. 以下T行,每行2个整数n和h. Output 共T行,每行一个整数表示答案(对1000000007取模) Sample Input 2 2 1 3 2 Sample Output 2 4 HINT 对于100%的数据,1<=n<=600,0<=h<=60

【BZOJ4033】[HAOI2015]树上染色 树形DP

[BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益.问收益最大值是多少. Input 第一行两个整数N,K. 接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to). 输入保证所有点之间是联通的. N<=2000,0<=K&l

【BZOJ1899】[Zjoi2004]Lunch 午餐 贪心+DP

[BZOJ1899][Zjoi2004]Lunch 午餐 Description 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的.另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的. THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排

【BZOJ3640】JC的小苹果 概率DP+高斯消元

[BZOJ3640]JC的小苹果 Description 让我们继续JC和DZY的故事. “你是我的小丫小苹果,怎么爱你都不嫌多!” “点亮我生命的火,火火火火火!” 话说JC历经艰辛来到了城市B,但是由于他的疏忽DZY偷走了他的小苹果!没有小苹果怎么听歌!他发现邪恶的DZY把他的小苹果藏在了一个迷宫里.JC在经历了之前的战斗后他还剩下hp点血.开始JC在1号点,他的小苹果在N号点.DZY在一些点里放了怪兽.当JC每次遇到位置在i的怪兽时他会损失Ai点血.当JC的血小于等于0时他就会被自动弹出迷