BZOJ4566 [Haoi2016]找相同字符

给定两个字符串\(s和t\),要求找出两个字符串中所有可以相互匹配的子串对的数量

首先考虑可以怎么做,我们可以枚举\(t\)串的前缀\(t'\),然后找\(t'\)的后缀能和\(s\)串匹配上的数量

这部分做法和和求\(LCS\)差不多

我们首先根据\(s\)串建\(SAM\),然后计算出每个状态的\(endpos\)集合大小,我们现在想知道以当前状态\(u\)的最长串为后缀最多可以匹配多少子串,那么当前状态可以匹配的数量就是\((len[u]-len[link[u]])\cdot cnt[u]\),其中\(len[u]\)为状态\(u\)的最长串的长度\(cnt[u]\)为\(endpos\)集合的大小,即匹配位置数量乘上可以匹配的长度,同时如果当前状态能够匹配,那么其后缀链接所连的状态也都能匹配,因为后缀链接连的是当前状态的后缀,既然要匹配的串的后缀能匹配的状态\(u\),那么必然能匹配到\(link[u],link[link[u]]\cdots\),所以我们要把\(parent\)中父节点的贡献下传,记当前状态\(u\)的最长串为后缀最多可以匹配的子串数量为\(f[u]\)

现在预处理完\(s\)串之后,我们在\(SAM\)上跑\(t\)串,对于每一个前缀,就相当于在上一个前缀的后面加上一个字符,那么就是在之前串所到的状态往后跑,如果上一个状态没有新的字符的连边,那么就跑他的后缀链接,直到到初始点或者找到有连边的节点,然后统计当前状态的答案,答案就是\(f[link[u]]+cnt[u]\cdot (matchlen-len[link[u]])\),其中\(matchlen\)为\(t\)串的这个前缀\(t'\)的后缀和\(s\)串能匹配的最长长度,由于当前状态里的所有长度不一定都可以匹配,所以不能直接算加上\(f[u]\),具体可以看代码

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef long long int LL;
const int MAXN = 4e5+7;
struct SAM{
int len[MAXN],link[MAXN],ch[MAXN][26],tot,last,cnt[MAXN],c[MAXN],sa[MAXN];
LL f[MAXN];
SAM(){ link[0] = -1; }
void extend(int c){
int np = ++tot, p = last;
len[np] = len[p] + 1; cnt[np] = 1;
while(p!=-1 and !ch[p][c]){
ch[p][c] = np;
p = link[p];
}
if(p==-1) link[np] = 0;
else{
int q = ch[p][c];
if(len[p] + 1 == len[q]) link[np] = q;
else{
int clone = ++tot;
len[clone] = len[p] + 1;
link[clone] = link[q];
memcpy(ch[clone],ch[q],sizeof(ch[q]));
link[np] = link[q] = clone;
while(p!=-1 and ch[p][c]==q){
ch[p][c] = clone;
p = link[p];
}
}
}
last = np;
}
void Radix_sort(){
for(int i = 0; i <= tot; i++) c[i] = 0;
for(int i = 0; i <= tot; i++) c[len[i]]++;
for(int i = 1; i <= tot; i++) c[i] += c[i-1];
for(int i = tot; i >= 0; i--) sa[c[len[i]]--] = i;
}
LL solve(char *s){
Radix_sort();
for(int i = tot + 1; i >= 2; i--) cnt[link[sa[i]]] += cnt[sa[i]];
for(int i = 2; i <= tot + 1; i++){
int u = sa[i];
f[u] = f[link[u]] + 1ll * cnt[u] * (len[u] - len[link[u]]);
}
int u = 0, ls = 0;
LL ret = 0;
for(int i = 0, l = strlen(s); i < l; i++){
int c = s[i] - 'a';
while(u and !ch[u][c]) u = link[u], ls = len[u];
if(ch[u][c]) u = ch[u][c], ls++;
if(!u) continue;
ret = ret + f[link[u]] + (ls-len[link[u]]) * cnt[u];
}
return ret;
}
}sam;
char s[MAXN];
int main(){
scanf("%s",s);
for(int i = 0, l = strlen(s); i < l; i++) sam.extend(s[i]-'a');
scanf("%s",s);
printf("%lld\n",sam.solve(s));
return 0;
}

BZOJ4566 [Haoi2016]找相同字符【SAM】的更多相关文章

  1. BZOJ4566:[HAOI2016]找相同字符(SAM)

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  2. [Bzoj4566][Haoi2016]找相同字符(广义后缀自动机)

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 861  Solved: 495[Submit][Statu ...

  3. [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1212  Solved: 694[Submit][Stat ...

  4. BZOJ4566 [Haoi2016]找相同字符 字符串 SAM

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4566.html 题目传送门 - BZOJ4566 题意 给定两个字符串 $s1$ 和 $s2$ ,问有 ...

  5. BZOJ4566: [Haoi2016]找相同字符

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  6. BZOJ4566: [Haoi2016]找相同字符(后缀自动机)

    题意 题目链接 Sol 直接在SAM上乱搞 枚举前缀,用SAM统计可以匹配的后缀,具体在匹配的时候维护和当前节点能匹配的最大值 然后再把parent树上的点的贡献也统计上,这部分可以爆跳parent树 ...

  7. BZOJ4566 Haoi2016 找相同字符【广义后缀自动机】

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  8. BZOJ4566 HAOI2016找相同字符(后缀自动机)

    对第一个串建SAM,第二个串在上面跑,记录当前前缀匹配的最长后缀长度l,每次考虑当前前缀的贡献,对于当前所在节点显然是|right|*(l-len[fa]),而对于其parent树上所有祖先的贡献显然 ...

  9. BZOJ4566 [Haoi2016]找相同字符 【后缀数组】

    题目 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. 输入格式 两行,两个字符串s1,s2,长度分别为n1,n2.1 & ...

随机推荐

  1. 【JDBC核心】获取数据库连接

    获取数据库连接 要素一:Driver 接口实现类 Driver 接口: java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口.这个接口是提供给数据库厂商使用的,不同数据库厂商提 ...

  2. linux硬盘分区和fdisk命令

    分区的几个概念 硬盘分区有三种,主分区.扩展分区.逻辑分区.一个硬盘主分区至少有1个,最多4个,扩展分区可以没有,最多1个.且主分区+扩展分区总共不能超过4个.逻辑分区可以有若干个.在windows下 ...

  3. 关于SSRF与CSRF漏洞的解释

    目录 SSRF服务端请求伪造(外网访问内网) 1.SSRF形成原因 2.利用SSRF漏洞的目的 3.SSRF漏洞的用途 4.SSRF漏洞的特性 实例 5.如何挖掘SSRF漏洞 6.常用SSRF去做什么 ...

  4. leetcode 1240. 铺瓷砖(回溯,DFS)

    题目链接 https://leetcode-cn.com/problems/tiling-a-rectangle-with-the-fewest-squares/ 题意: 用尽可能少的正方形瓷砖来铺地 ...

  5. Sentinel上下文创建及执行

    Sentinel上下文创建及执行,入口示例代码: public static void fun() { Entry entry = null; try { entry = SphU.entry(SOU ...

  6. centos7搭建dolphinscheduler集群

    一.简述 Apache DolphinScheduler是一个分布式去中心化,易扩展的可视化DAG工作流任务调度系统.致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数据处理流程中开箱即用.有 ...

  7. Redis 实战 —— 06. 持久化选项

    持久化选项简介 P61 Redis 提供了两种不同的持久化方法来将数据存储到硬盘里面. RDB(redis database):可以将某一时刻的所有数据都写入硬盘里面.(保存的是数据本身) AOF(a ...

  8. MATLAB中load和imread的读取方式区别

    load是导入文件,一般从mat文件中,读取的是结构体imread是图像处理工具箱的库函数,处理图像比较方便,读取的是矩阵 1.之前将数组或者矩阵保存为一个mat格式的文件,在进行load命令读取时: ...

  9. 前端工程构建之谈:gulp3要不要升级到Gulp4

    关于升级还是不升级,这是一个哲学问题. gulp4的语法更加现代,支持ES6的大部分写法,使用exports的方式去暴露任务组合,更加灵活和便捷. gulp4同时也提供了很多强大的API,例如para ...

  10. ORM框架对比以及Mybatis配置文件详解

    ORM框架对比以及Mybatis配置文件详解 0.数据库操作框架的历程 (1) JDBC ​ JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句 ...