最近几天一直在做有关后缀自动机的题目

感觉似乎对后缀自动机越来越了解了呢!喵~

这题还是让我受益颇多的,首先搞一个后缀自动机是妥妥的了

可是搞完之后呢?

我们来观察 step 这个变量,每个节点的 step 是从根节点到此节点所经过的最长步数

那么也就是以该点为结尾的最长的后缀长度

如何统计不被 Bi 串包含的子串呢?

其实很简单,维护每个节点所能匹配的最长的字符串长度

然后 节点->step-max(该节点所能匹配的最长的字符串长度, 节点->fail->step) 就是答案了

因为 S[0..节点->step-1] 必是原串的一个后缀,而 节点所能匹配的最长字符串长度 d 说明 S[节点->step-d..节点->step-1] 是出现在了某个 Bi 串中的

只不过把每个串在自动机上跑一遍并不能得到每个节点所能匹配的最长长度

因为当该节点被匹配时,该结点的 fail 指针所指向的节点也必然被匹配到了

我们需要一个拓扑排序,按拓扑序来更新答案,并同时更新每个节点的 fail 指针指向的点的匹配长度

教练,我不想写拓扑排序~

我才不会说按 step 从大到小的顺序就是拓扑序呢喵~

namespace 写写被 hdu 怒骂 TLE TAT ,这是多么痛的领悟……

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define ord(ch) ((ch)-'a')
typedef long long llint;
const int sizeOfString=;
const int sizeOfMemory=<<;
const int sizeOfType=; inline int max(int x, int y) {return x>y?x:y;} struct node
{
int step;
int same;
node * fail;
node * ch[sizeOfType];
};
node memory[sizeOfMemory]; int port;
node * dfa=memory, * last;
inline node * newnode(node * t=NULL)
{
node * newt=memory+(port++);
newt->step=;
newt->same=;
if (t) newt->fail=t->fail, t->fail=newt, memcpy(newt->ch, t->ch, sizeof t->ch);
else newt->fail=NULL, memset(newt->ch, , sizeof newt->ch);
return newt;
}
inline void insert(int w)
{
node * p=last, * newp=newnode();
newp->step=p->step+; for ( ;p->ch[w]==NULL;p=p->fail) p->ch[w]=newp;
if (p->ch[w]==newp)
newp->fail=dfa;
else
{
node * q=p->ch[w];
if (q->step==p->step+)
newp->fail=q;
else
{
node * newq=newnode(q);
newq->step=p->step+;
newp->fail=newq;
for ( ;p->ch[w]==q;p=p->fail) p->ch[w]=newq;
}
} last=newp;
}
inline void search(char * s)
{
int len=strlen(s);
int tot=;
node * t=dfa;
for (int i=;i<len;i++)
{
int w=ord(s[i]);
if (t->ch[w])
{
t=t->ch[w];
t->same=max(t->same, ++tot);
}
else
{
node * j;
for (j=t->fail;j!=dfa && !j->ch[w];j=j->fail);
if (j->ch[w])
{
t=j->ch[w];
t->same=max(t->same, tot=(j->step+));
}
else
{
t=dfa;
tot=;
}
}
}
}
inline llint calc(int len)
{
static node * p[sizeOfMemory];
static int cnt[sizeOfString];
llint ret=; memset(cnt, , sizeof(cnt));
for (int i=;i<port;i++) cnt[dfa[i].step]++;
for (int i=;i<=len;i++) cnt[i]+=cnt[i-];
for (int i=;i<port;i++) p[--cnt[dfa[i].step]]=&dfa[i];
for (int i=port-;i>;i--)
{
p[i]->fail->same=max(p[i]->fail->same, p[i]->same);
if (p[i]->same<p[i]->step)
ret+=p[i]->step-max(p[i]->same, p[i]->fail->step);
} return ret;
} int T, n;
char str[sizeOfString], s[sizeOfString]; int main()
{
int cases=; for (scanf("%d", &T);T;T--)
{
scanf("%d", &n);
scanf("%s", str);
port=; dfa=newnode(); dfa->fail=dfa; last=dfa;
int len=strlen(str);
for (int i=;i<len;i++)
insert(ord(str[i]));
for (int i=;i<=n;i++)
{
scanf("%s", s);
search(s);
}
printf("Case %d: %I64d\n", ++cases, calc(len));
} return ;
}

本傻装B不成反被艹系列

[hdu 4416]Good Article Good sentence的更多相关文章

  1. HDU 4416 Good Article Good sentence(后缀自动机)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4416 [题目大意] 给出一个字符串,然后,给出一个字符串集合,问在该字符串中出现,且不在字符串集合 ...

  2. HDOJ 4416 Good Article Good sentence

    题解转自:http://blog.csdn.net/dyx404514/article/details/8807440 2012杭州网络赛的一道题,后缀数组后缀自己主动机都行吧. 题目大意:给一个字符 ...

  3. HDU 4416 (后缀自动机)

    HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...

  4. Good Article Good sentence HDU - 4416 (后缀数组)

    Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...

  5. Good Article Good sentence HDU - 4416 (后缀自动机)

    Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...

  6. hdu 3507 Print Article(斜率优化DP)

    题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...

  7. HDU 3507 - Print Article - [斜率DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3507 Zero has an old printer that doesn't work well s ...

  8. HDU 3507 Print Article 斜率优化

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  9. HDU 3507 Print Article(DP+斜率优化)

     Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) ...

随机推荐

  1. [C/C++]C++标准中的名词

    1.qualified-id.nested-name-specifier: [example: struct A { struct B { void F(); }; }; A is an unqual ...

  2. MySQL v5.1.72 + v5.6.19

    MYSQL是一个多线程的,结构化查询语言(SQL)数据库服务器.SQL 在世界上是最流行的数据库语言.MySQL 的执行性能非常高,运行速度非常快,并非常容易使用.是一个非常捧的数据库. MySQL ...

  3. CentOS SSH配置

    默认CentOS已经安装了OpenSSH,即使你是最小化安装也是如此.所以这里就不介绍OpenSSH的安装了. SSH配置: 1.修改vi /etc/ssh/sshd_config,根据模板将要修改的 ...

  4. LINQ基础 之 LINQ TO SQL (二)

    配置LINQ TO SQL 首先添加一个Linq to sql文件,以.dbml结尾的文件.无法把表拖拽到.dbml文件中,提示“所选对象使用不支持的数据提供程序” 解决方案 在服务器资源管理器中右键 ...

  5. php访问数据库思维导图

  6. IOS四种保存数据的方式

    在iOS开发过程中,不管是做什么应用,都会碰到数据保存的问题.将数据保存到本地,能够让程序的运行更加流畅,不会出现让人厌恶的菊花形状,使得用户体验更好.下面介绍一下数据保存的方式: 1.NSKeyed ...

  7. self进行weak化

    创建block匿名函数之前一般需要对self进行weak化,否则造成循环引用无法释放controller: __weak MyController *weakSelf = self 或者 __weak ...

  8. JS 验证一组input框是否为空的方法

    function checkInput() { var $tr = $("#tb_confirmed .scrollContent").find("tr"); ...

  9. Mysql 基本操作连接数据库读取信息内容

    <?php header("content-type:text/html; charset=utf-8"); // 数据库配置信息 define("DB_HOST& ...

  10. iOS打包为ipa的两种方式和生成P12证书的方式

    iOS项目打包为ipa的两种方式: 准备工作:先行在Xcode里面打开preferences,填写apple id. 通过iTunes+Xcode 在Xcode里,把模拟器调整为iOS Device, ...