后缀自动机感觉好万能

tries图和ac自动机能做的,后缀自动机很多也都可以做

这里的循环匹配则是后缀自动机能做的另一个神奇功能

循环匹配意思就是S是abba, T是abb

问'abb', 'bba','bab'在S中出现过多少次。

我们先把T的末尾循环加一遍,变成abbab

然后把问题转换成,求T的每个后缀和S的最长公共子串

如果最长公共子串的长度大于等于T的长度,那么就说明这个后缀匹配成功

做法就是先对S建立一个后缀自动机,然后记录一个状态

(u, l),u表示当前在后缀自动机匹配的位置,l表示最长公共子串的长度

考虑转移的话,就是

如果下一个位置可以匹配,那么u就到相应的位置,l = l+1

答案更新的时候要注意,如果l大于T的长度len,就需要顺着link往前走到第一个能匹配的位置,即第一个maxlen[x] >= len的地方,然后答案加上endpos[x],不然会丢一部分答案。

如果下一个位置不可以匹配,那么u就顺着link边走,走到第一个能匹配的地方,如果找不到,那u就设成起点,l为0

还有一个问题就是串重复的情况,比如说T是aa,那么扩充就会变成aaa,aa和aa重复。

如果串重复的话,那么必定会到同一个状态,所以一个状态标记一下,只更新一遍答案就可以了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
using namespace std;
int n = , len, st;
const int maxL = 1e6 + ;
int maxlen[*maxL], minlen[*maxL], trans[*maxL][], slink[*maxL], lab[*maxL], son[*maxL], endpos[*maxL];
map<int, bool> vis;
int new_state(int _maxlen, int _minlen, int *_trans, int _slink){
maxlen[n] = _maxlen;
minlen[n] = _minlen;
for(int i = ; i < ; i++){
if(_trans == NULL)
trans[n][i] = -;
else
trans[n][i] = _trans[i];
}
slink[n] = _slink;
return n++;
} int add_char(char ch, int u){
int c = ch - 'a';
int z = new_state(maxlen[u]+, -, NULL, -); lab[z] = ;
int v = u;
while(v != - && trans[v][c] == -){
trans[v][c] = z;
v = slink[v];
}
if(v == -){
minlen[z] = ;
slink[z] = ;
return z;
}
int x = trans[v][c];
if(maxlen[v] + == maxlen[x]){
minlen[z] = maxlen[x] + ;
slink[z] = x;
return z;
}
int y = new_state(maxlen[v] + , -, trans[x], slink[x]);
slink[y] = slink[x];
minlen[x] = maxlen[y] + ;
slink[x] = y;
minlen[z] = maxlen[y] + ;
slink[z] = y;
int w = v;
while(w != - && trans[w][c] == x){
trans[w][c] = y;
w = slink[w];
}
minlen[y] = maxlen[slink[y]] + ;
return z;
} char str[maxL];
int main()
{
cin>>str;
st = new_state(, , NULL, -);
int len = strlen(str);
for(int i = ; i < len; i++) {
st = add_char(str[i], st);
}
for(int i = ; i <= n; i++) son[slink[i]]++;
queue<int> Q;
for(int i = ; i <= n; i++) if(son[i] == ) Q.push(i), endpos[i] = ;
while(!Q.empty()){
int x = Q.front(); Q.pop();
if(x == ) continue;
int y = slink[x];
son[y]--; endpos[y] += endpos[x];
if(son[y] == ){
if(lab[y]) endpos[y]++;
Q.push(y);
}
}
int T;
cin>>T;
while(T--){
vis.clear();
cin>>str;
int len = strlen(str), ylen = len;
for(int i = len; i < *len-; i++) str[i] = str[i-len];
len = *len-;
int u = , l = , ans = ;
for(int i = ; i < len; i++){
int c = str[i] - 'a';
if(trans[u][c] != -){
u = trans[u][c];
l++;
} else {
int y = slink[u];
while(y != -){
if(trans[y][c] != -){
l = maxlen[y] + ;
u = trans[y][c];
break;
}
u = y;
y = slink[u];
}
if(y == -) { u = ; l = ; }
}
if(l >= ylen){
int y = slink[u];
while(maxlen[y] >= ylen) { u = y; y = slink[u]; l = maxlen[u]; }
if(vis[u]) continue;
vis[u] = ;
ans += endpos[u];
}
}
cout<<ans<<endl;
}
return ;
}

hihocoder 1465 循环串匹配问题(后缀自动机)的更多相关文章

  1. hiho# 1465 重复旋律8 循环串计数 后缀自动机

    题目传送门 题意:给出一个母串,再给出n个串,问对于每个串,母串中有几个子串是可以通过循环变化得到这个串. 思路:对母串建SAM,求出$right$集. 把匹配串复制一遍,和母串进行匹配,当匹配长度大 ...

  2. hihoCoder #1465 : 后缀自动机五·重复旋律8

    http://hihocoder.com/problemset/problem/1465 求S的循环同构串在T中的出现次数 将串S变成SS 枚举SS的每个位置i,求出以i结尾的SS的子串 与 T的最长 ...

  3. hihocoder 后缀自动机五·重复旋律8 求循环同构串出现的次数

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以 ...

  4. 后缀自动机专题(hihocoder)

    传送门 #1445 : 后缀自动机二·重复旋律5 题意: 给出字符串\(s\),询问字符串\(s\)中有多少不同的子串. 思路: 考虑对\(s\)建后缀自动机,那么\(\sum (len[i]-len ...

  5. 【hihocoder#1413】Rikka with String 后缀自动机 + 差分

    搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...

  6. hihoCoder 后缀自动机三·重复旋律6

    后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...

  7. 【hihoCoder 1466】后缀自动机六·重复旋律9

    http://hihocoder.com/problemset/problem/1466 建出A串和B串的两个后缀自动机 对后缀自动机的每个状态求出sg值. 求出B串的\(sum(x)\),表示B有多 ...

  8. hihocoder 后缀自动机专题

    一.后缀自动机基本概念的理解 1.首先后缀自动机的状态是由子串的endpos来决定的 子串的endpos是指一个子串可以在原字符串的哪些位置进行匹配, endpos构成的不同集合划分成不同的状态 关于 ...

  9. hiho一下第131周 后缀自动机二·重复旋律8(循环相似子串)

    后缀自动机五·重复旋律8 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi ...

随机推荐

  1. 路由器基础配置之ppp封装下的pap,chap认证

    我们将以上面的拓扑图完成本次实验,路由器的默认封装为HDLC,要求为把路由器全被更改为ppp封装,并在router3与router4之间用pap认证,在router4与router5之间用chap认证 ...

  2. jquery图片滚动jquery.scrlooAnimation.js

    ;(function ($, window, document, undefined) { var pluginName = "scrollAnimations", /** * T ...

  3. jsp传参 servlet接收中文乱码问题

    在公司实习了8个月,一直都是做android和h5的,但是发现做程序连一点服务都不会该怎么办,所以最近开始学起了java,不知道是不是因为框架学多了,现在看起springmvc框架比以前看起来简单太多 ...

  4. PHP中有关IPV4 和IPV6地址转换以及其它一些常见问题

    这里主要介绍一下 IPV4 / IPV6 在 PHP / MySQL 中如何转换.以及中间容易碰到的一些问题. 首先介绍两个函数: ip2long:将 IPV4 的字符串互联网协议转换成长整型数字 i ...

  5. php 无限参数方法

    在很多项目开发中经常会用到共用方法但是参数不固定,每个参数都创建一遍阅读性不好,后期维护也麻烦,PHP有获取传入参数的方法,记录参考一下.这里有两个方法 <?php 方法一: #不指定参数个数方 ...

  6. STM32F4使用FPU+DSP库进行FFT运算的测试过程二

    原文地址:http://www.cnblogs.com/NickQ/p/8541156.html 测试环境:单片机:STM32F407ZGT6 IDE:Keil5.20.0.0 固件库版本:STM32 ...

  7. C语言常用关键语法精华总结

    1.关于typedef的用法总结 2.typedef struct的用法 3.typedef函数指针用法 4.数组指针(数组类型的指针)与指针数组 5.真正明白c语言二级指针 6.C语言for循环(及 ...

  8. 【JDBC】一、JDBC连接数据库

    package com.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLExce ...

  9. responsive grid

    http://csswizardry.com/csswizardry-grids/ http://unsemantic.com/demo-responsive http://getbootstrap. ...

  10. c# string.format和tostring()

    字符 说明 示例 输出 C 货币 string.Format("{0:C3}", 2) $2.000 D 十进制 string.Format("{0:D3}", ...