hihocoder 1465 循环串匹配问题(后缀自动机)
后缀自动机感觉好万能
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 循环串匹配问题(后缀自动机)的更多相关文章
- hiho# 1465 重复旋律8 循环串计数 后缀自动机
题目传送门 题意:给出一个母串,再给出n个串,问对于每个串,母串中有几个子串是可以通过循环变化得到这个串. 思路:对母串建SAM,求出$right$集. 把匹配串复制一遍,和母串进行匹配,当匹配长度大 ...
- hihoCoder #1465 : 后缀自动机五·重复旋律8
http://hihocoder.com/problemset/problem/1465 求S的循环同构串在T中的出现次数 将串S变成SS 枚举SS的每个位置i,求出以i结尾的SS的子串 与 T的最长 ...
- hihocoder 后缀自动机五·重复旋律8 求循环同构串出现的次数
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以 ...
- 后缀自动机专题(hihocoder)
传送门 #1445 : 后缀自动机二·重复旋律5 题意: 给出字符串\(s\),询问字符串\(s\)中有多少不同的子串. 思路: 考虑对\(s\)建后缀自动机,那么\(\sum (len[i]-len ...
- 【hihocoder#1413】Rikka with String 后缀自动机 + 差分
搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...
- hihoCoder 后缀自动机三·重复旋律6
后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...
- 【hihoCoder 1466】后缀自动机六·重复旋律9
http://hihocoder.com/problemset/problem/1466 建出A串和B串的两个后缀自动机 对后缀自动机的每个状态求出sg值. 求出B串的\(sum(x)\),表示B有多 ...
- hihocoder 后缀自动机专题
一.后缀自动机基本概念的理解 1.首先后缀自动机的状态是由子串的endpos来决定的 子串的endpos是指一个子串可以在原字符串的哪些位置进行匹配, endpos构成的不同集合划分成不同的状态 关于 ...
- hiho一下第131周 后缀自动机二·重复旋律8(循环相似子串)
后缀自动机五·重复旋律8 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi ...
随机推荐
- spring-运行时值注入
在项目中经常使用连接数据库的配置,如下所示 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDa ...
- 首层nginx 传递 二级代理,三级代理......多级代理nginx 客户端真实IP的方法
首层nginx(172.25.10.1):先获取真实IP($remote_addr),再将真实IP传递给X-Forwarded-For proxy_set_header X-Real-IP $r ...
- ZooKeeper(1)-入门
一. Zookeeper工作机制 二.Zookeeper特点 三.Zookeeper数据结构 四.Zookeeper应用场景 统一命名服务 统一配置管理 统一集群管理 服务器动态上下线 软负载均衡
- python 装饰器 (多个装饰器装饰一个函数---装饰器前套一个函数)
#带参数的装饰器 #500个函数 # import time # FLAGE = False # def timmer_out(flag): # def timmer(func): # def inn ...
- 笔记-python-常见特殊变量
笔记-python-常见特殊变量 类似__xx,以双下划线开头的实例变量名,就变成了一个私有变量(private),只有内部可以访问,外部不能访问: 类似__xx__,以双下划线开头,并且以双下划线结 ...
- JAVA大作业汇总1
JAVA大作业 代码 ``` package thegreatwork; import javafx.application.; import javafx.scene.control.; impor ...
- PHP通过copy()函数来复制一个文件
PHP通过copy()函数来复制一个文件.用法如下: bool copy(string $source, string $dest) 其中$source是源文件的路径,$dest是目的文件的路径.函数 ...
- NSDictionary底层实现原理
一言以蔽之:在OC中NSDictionary是使用hash表来实现key和value的映射和存储的. 那么问题来了什么是hash表呢? 哈希表(hash表): 又叫做散列表,是根据关键码值(key v ...
- PostgreSQL 10.0 压缩版的 pgAdmin 不能用的问题
PostgreSQL终于发布10.0正式版了!下载压缩版的更新了一下本机的版本,然后打开pgAdmin的时候总是报错“The application server could not be conta ...
- Linux-Shell脚本编程-学习-2-Linux基本命令
接上篇,接着学习Linux下的部分命令,后面的这些命令用到的频率可能没有那么多,不过也是经常需要的. 第一部分:程序监测部分,ps和top top命令可能比较眼熟,所以我们先说ps ps命令最烦人了, ...