bzoj 1212 [HNOI2004] L语言(不用AC自动机)

网上的题解大多树都要建一棵trie树,并在上面跑AC自动机,然而这里有一种同样需要trie树,但时间复杂度较低的方法。

首先,我们可以轻松列出状态转移方程 F[x]=∑| F[x-len(i)]&(is(i->x,s[i]);

这样的复杂度是O(m*lens*∑len[i]*n),可能会超时,再加上hash之类的就可以过了,但这显然不优美。

====================分割线====================

对于每个F(i),我们都是从之前的额某个F(j)转移过来的,它是true当且仅当(j+1->i)是一个单词,且f[j]是true,那么我们将每个单词反过来建一棵trie树,例如有单词abc,我们将cba插入trie树,从i开始i先匹配到每个单词的最后一位,然后再匹配到最后一位相同的倒数第二位,如此下去,当我们匹配到一个单词的开头时,并且此时的F[i-depth]为true的话,F(i)就为true了,因为每个字符在trie树上的路径唯一,且trie树的深度不超过单词的最长长度(10),所以它的复杂度还是非常可看的,复杂度为O(m*lens*dep(trie))=O(m*lens*max(strlen(word))),20*1M*10,轻松过。

这题不难,但是如果反过来想,可以避免很多高端算法,从后往前的思想确实不错。贴一个代码,有些冗长。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 using namespace std;
 6 int ch[10005][20];
 7 int cnt;
 8 int n,m;
 9 char s[2000005];
10 int col[2000005];
11 bool dp[1000005];
12 void insert()
13 {
14     int now=0;
15     for(int i=strlen(s)-1;i>=0;i--)
16     {
17         int c=s[i]-‘0‘;
18         if(!ch[now][c])
19         {
20             cnt++;
21             ch[now][c]=cnt;
22         }
23         now=ch[now][c];
24     }
25     col[now]=true;
26 }
27 bool cal(int x)
28 {
29     int deep=0;
30     int now=0;
31     for(int i=x;i>=1;i--)
32     {
33         int c=s[i]-‘0‘;
34         if(ch[now][c]==0)return false;
35         now=ch[now][c];
36         deep++;
37         if(dp[x-deep] && col[now])return true;
38     }
39     return true;
40 }
41 void solve()
42 {
43     int ll=strlen(s+1);
44     for(int i=1;i<=ll;i++)
45     {
46         dp[i]=cal(i);
47     }
48     for(int i=ll;i>=0;i--)
49     {
50         if(dp[i])
51         {
52             printf("%d\n",i);
53             return;
54         }
55     }
56     return ;
57 }
58 int main()
59 {
60     scanf("%d%d",&n,&m);
61     for(int i=1;i<=n;i++)
62     {
63         scanf("%s",s);
64         insert();
65     }
66     for(int i=1;i<=m;i++)
67     {
68         memset(dp,0,sizeof(dp));
69         dp[0]=true;
70         scanf("%s",s+1);
71         solve();
72     }
73     return 0;
74 }

时间: 2024-10-27 18:46:44

bzoj 1212 [HNOI2004] L语言(不用AC自动机)的相关文章

BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]

1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1367  Solved: 598[Submit][Status][Discuss] Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的集合. 我们称一段文章T在某个字典D下是可以被理解的,是指如果文

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

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

BZOJ 1212 HNOI2004 L语言 AC自动机(Trie树)+动态规划

题目大意:给定一个单词表和m个字符串 问每个字符串的最长的前缀,满足这个前缀可以拆分成一些字符串 使这些字符串都在单词表中出现过 再也不敢看错数据范围了--一道明明用Trie树能解决的问题居然被我写了AC自动机-- 将单词表中的单词全都插入AC自动机 每个单词所在的节点记录这个单词的长度 然后对于每个字符串 用f[i]表示长度为i的前缀是否能拆分成单词表中的单词 跑AC自动机 对于每个匹配的节点 从这个节点开始到根的fail路径上的所有len f[i]|=f[i-len] 找到最大的为1的f[i

1212: [HNOI2004]L语言

1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 643  Solved: 252[Submit][Status] Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的集合. 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部

【BZOJ1212】L语言(AC自动机)

[BZOJ1212]L语言(AC自动机) 题面 BZOJ 题解 很自然的,既然要匹配单词,那就全部都丢到\(AC\)自动机里面去 现在想想怎么匹配 先是\(AC\)自动机正常的匹配 如果此时这个位置能够匹配上一个串 我们就需要判断一下这个串覆盖到这个文本串中 它的前一位是否恰好被覆盖 如果有的话 我们也不能直接计算 因为可能是其他不同的串拼起来的 所以,就开一个数组差分 表示当前位置可以匹配 最后,对于每个文本串 从前往后扫一遍差分数组 直到有\(0\)的地方就直接输出就行啦 #include<

[BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】

题目链接:BZOJ - 3530 题目分析 明显是 AC自动机+DP,外加数位统计. WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多.. 其实现在做这道题,我自己也没想出完整解法.. 就想出了个 O(l^3) 的做法: 完全按照数位统计的思想来,先统计长度不足 len 的数字的合法种类数,这个枚举开头,然后 AC 自动机 DP 一下,用 f[i][j] 表示到了第 i 位,在第 j 个节点上的合法数字个数.这样是 O(L^2). 然后长度等于 n 的部分,就按照数位统计,一位位向

BZOJ 1030 [JSOI2007]文本生成器(AC自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1030 [题目大意] 求出包含任意一个给定串的串数量 [题解] 我们求出不包含任意一个给定串的数量,用全集去减即可, 对于给定串建立AC自动机,用1节点作为根,0节点向1连全字符集转移作为超级源, 那么0->match能匹配所有不包含给定串的串, 记dp[i][j]表示匹配了i长度,匹配到AC自动机j节点的串数量, 统计之后取补集即可. [代码] #include <cstdio&g

bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3059  Solved: 1255[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6