BZOJ4566 Haoi2016 找相同字符【广义后缀自动机】
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两
个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabb
bbaa
Sample Output
10
可以说是模板了
因为只有两个串,所以完全没有必要建trie
直接分别添加,在每个串开始添加之前让last=root就可以了
然后在extend上面加上已经有转移的特判
注意要后缀自动机建完之后再添加right标记
不然会出问题
//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define for_up(a, b, c) for (int a = b; a <= c; ++a)
#define for_down(a, b, c) for (int a = b; a >= c; --a)
#define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x){
bool w = 1;x = 0;
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-')w = 0, c = getchar();
while(isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if(!w)x=-x;
}
template <typename T>
void Write(T x){
if(x < 0) {
putchar('-');
x=-x;
}
if(x > 9)Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
const int CHARSET_SIZE = 26;
const int N = 4e5 + 10;
struct Sam {
Sam *ch[CHARSET_SIZE], *prt;
int maxl, right[2];
Sam (int maxl = 0):ch(),prt(NULL),maxl(maxl){
right[0] = right[1] = 0;
}
}pool[N<<1],*cur = pool, *root = new (cur++)Sam, *last = root;
int buc[N];
vector<Sam*> topo;
ll ans = 0;
void extend(int c){
if (last->ch[c] && last->maxl + 1 == last->ch[c]->maxl) {
last = last->ch[c];
return;
}
Sam *u = new (cur++)Sam(last->maxl + 1), *v = last;
for (; v && !v->ch[c]; v = v->prt) v->ch[c] = u;
if (!v) {
u->prt = root;
} else if (v->maxl + 1 == v->ch[c]->maxl) {
u->prt = v->ch[c];
} else {
Sam *n = new (cur++)Sam(v->maxl + 1), *o = v->ch[c];
copy(o->ch, o->ch + CHARSET_SIZE, n->ch);
n->prt = o->prt;
o->prt = u->prt = n;
for (; v && v->ch[c] == o;v = v->prt) v->ch[c] = n;
}
last = u;
}
void toposort(){
int maxv = 0;
for (Sam *p = pool; p != cur; ++p){
maxv = max(maxv, p->maxl);
buc[p->maxl]++;
}
for_up(i, 1, maxv) buc[i] += buc[i-1];
topo.resize(cur-pool);
for (Sam *p = pool; p != cur; ++p)topo[--buc[p->maxl]] = p;
for_down(i, topo.size()-1, 1) {
Sam *p = topo[i];
p->prt->right[0] += p->right[0];
p->prt->right[1] += p->right[1];
ans += 1ll * (p->maxl - p->prt->maxl) * p->right[0] * p->right[1];
}
}
char c[2][N];
int main() {
scanf("%s",c[0] + 1);
int len0 = strlen(c[0] + 1);
for_up(i, 1, len0) extend(c[0][i]-'a');
last = root;
scanf("%s",c[1] + 1);
int len1 = strlen(c[1] + 1);
for_up(i, 1, len1) extend(c[1][i]-'a');
Sam *now = root;
for_up(i, 1, len0) {
now = now->ch[c[0][i]-'a'];
now->right[0] = 1;
}
now = root;
for_up(i, 1, len1) {
now = now->ch[c[1][i]-'a'];
now->right[1] = 1;
}
toposort();
Write(ans);
return 0;
}
BZOJ4566 Haoi2016 找相同字符【广义后缀自动机】的更多相关文章
- [HAOI2016]找相同字符 广义后缀自动机_统计出现次数
题目描述:给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 输入输出格式输入格式:两行,两个字符串 s1,s2,长度分别为n ...
- BZOJ 4566 [Haoi2016]找相同字符 ——广义后缀自动机
建立广义后缀自动机. 然后统计子树中的siz,需要分开统计 然后对(l[i]-l[fa[i]])*siz[i][0]*siz[i][1]求和即可. #include <cstdio> #i ...
- bzoj 4566 [Haoi2016]找相同字符——广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4566 每个后缀结尾处 ct[ ] = 1 ,按拓扑序 dp 一下就能求出 right 集合的 ...
- BZOJ4566 HAOI2016找相同字符(后缀自动机)
对第一个串建SAM,第二个串在上面跑,记录当前前缀匹配的最长后缀长度l,每次考虑当前前缀的贡献,对于当前所在节点显然是|right|*(l-len[fa]),而对于其parent树上所有祖先的贡献显然 ...
- BZOJ4566&&lg3181 HAOI找相同字符(广义后缀自动机)
BZOJ4566&&lg3181 HAOI找相同字符(广义后缀自动机) 题面 自己找去 HINT 给定两个文本串,问从两个串中各取一个非空子串,使这俩子串相同,问方案有多少种.我的思路 ...
- BZOJ_4566_[Haoi2016]找相同字符_后缀自动机
BZOJ_4566_[Haoi2016]找相同字符_后缀自动机 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有 ...
- 【BZOJ4566】找相同字符(后缀自动机)
[BZOJ4566]找相同字符(后缀自动机) 题面 BZOJ 题解 看到多串处理,\(SA\)就连起来 \(SAM???\) 单串建自动机 然后其他串匹配 对于一个串建完\(SAM\)后 另一个串在\ ...
- bzoj 4566 找相同字符 —— 广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4566 建出两个串的广义后缀自动机: 统计每个点在两个串中出现次数的子树和,其实就是在两个串中 ...
- 【BZOJ4566】找相同字符【后缀自动机】
题意 给定两个字符串,求两个字符串相同子串的方案数. 分析 那么将字符串s1建SAM,然后对于s2的每个前缀,都在SAM中找出来,并且计数就行. 我一开始的做法是,建一个u和len,顺着s2跑SAM, ...
- BZOJ4566 [Haoi2016]找相同字符 【后缀数组】
题目 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. 输入格式 两行,两个字符串s1,s2,长度分别为n1,n2.1 & ...
随机推荐
- 分析ReentrantLock的实现原理
http://www.jianshu.com/p/fe027772e156 什么是AQS AQS即是AbstractQueuedSynchronizer,一个用来构建锁和同步工具的框架,包括常用的Re ...
- HDFS读写流程learning
有许多对流程进行描述的博客,但是感觉还是应当学习一遍代码,不然总感觉怪怪的,https://blog.csdn.net/popsuper1982/article/details/51615285,首先 ...
- Matlab 日期频次统计
一.孕妇建档月份频次统计 源数据样本,为某医院一段时间内的孕妇建档时间 2015-04-22 10:12:522014-11-21 17:16:472013-12-16 17:35:442013-12 ...
- RestTemplate请求https忽略证书认证
RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率.RestTemplate 默认使用J2SE提供的方式( ...
- IIS和ASP.NET MVC 管道处理模型
转载自 博客园 青羽 http://www.cnblogs.com/tenghoo/archive/2009/11/04/IIS_And_ASPNET_Http_Runtime_Pipeline.h ...
- C++(二十七) — 深拷贝、浅拷贝、复制构造函数举例
1.复制构造函数.及new空间申请 复制构造函数,也是构造函数.只在初始化时调用,如果定义对象后赋值,比如,t1=t2,则只是运算符重载,没有调用构造函数. #include <iostream ...
- Regression 手动实现Gradient Descent
import numpy as np import matplotlib.pyplot as plt x_data = [338.,333.,328.,207.,226.,25.,179.,60.,2 ...
- Ansible 小手册系列 九(Playbook)
playbook是由一个或多个"play"组成的列表.play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色.从根本上来讲所谓task无非 ...
- 从HDC转换到leptonica PIX
void CAssistDlg::OnBnClickedTest() { HDC hdc = ::GetDC(NULL); HDC hdcMem = CreateCompatibleDC(hdc); ...
- Quartz教程一:使用quartz
原文链接 | 译文链接 | 翻译:nkcoder | 校对:方腾飞 本系列教程由quartz-2.2.x官方文档翻译.整理而来,希望给同样对quartz感兴趣的朋友一些参考和帮助,有任何不当或错误之处 ...