其实这道题跟[AHOI2013]差异很像

其实这个问题的本质就是让你算所有后缀的\(lcp\)长度之和,但是得来自两个不同的字符串

先把两个字符串拼起来做一遍\(SA\),由于我们多算了来自于同一个串内的情况

于是在分别对这两个串建\(SA\),减掉这两次算出来的答案

现在的问题转化为求出\(height\)数组所有子区间的最小值的和

我们可以考虑一个动态往序列末尾加数的过程

也就是我们往末尾加一个数都会和之前所有的数形成一个新的区间

考虑快速算出这些区间的最小值的和

我们可以对每一个数存储一个\(a_i\),表示\(i\)到当前序列末尾的最小值是多少

我们每次加入一个数可以对更新一下所有的\(a_i\),把所有比当前加入的数大的\(a_i\)变成当前数就好了

这不就\(T\)了吗

我们发现我们只需要求出所有\(a_i\)的和,并不需要关心这个\(i\)来自哪里,于是我们可以把相等的\(a_i\)放在一起计算,也就是每次新加入一个数就暴力扫一遍把那些比当前加入数大的合并到一个\(a_i\)里

看起来复杂度并不科学,但是最坏情况下就相当于是一个线段树的复杂度了,\(O(n)\)的,跑的还挺快的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define re register
#define LL long long
#define maxn 400005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
int het[maxn],sa[maxn],rk[maxn],tp[maxn],tax[maxn];
char S[maxn],T[maxn];
int L1,L2,n,m;
LL a[maxn],cnt[maxn],top;
LL tot;
inline void qsort()
{
for(re int i=0;i<=m;i++) tax[i]=0;
for(re int i=1;i<=n;i++) tax[rk[i]]++;
for(re int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(re int i=n;i;--i) sa[tax[rk[tp[i]]]--]=tp[i];
}
inline LL SA()
{
LL ans=0,sum=0;
memset(rk,0,sizeof(rk)),memset(sa,0,sizeof(sa)),memset(het,0,sizeof(het)),memset(tp,0,sizeof(tp));
memset(a,0,sizeof(a)),memset(cnt,0,sizeof(cnt)),top=0;
m=2500;
for(re int i=1;i<=n;i++) rk[i]=S[i],tp[i]=i;
qsort();
for(re int w=1,p=0;p<n;m=p,w<<=1)
{
p=0;
for(re int i=1;i<=w;i++) tp[++p]=n-w+i;
for(re int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
qsort();
for(re int i=1;i<=n;i++) std::swap(tp[i],rk[i]);
rk[sa[1]]=p=1;
for(re int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}
int k=0;
for(re int i=1;i<=n;i++)
{
if(k) --k;
int j=sa[rk[i]-1];
while(S[i+k]==S[j+k]) ++k;
het[rk[i]]=k;
}
for(re int i=2;i<=n;i++)
{
LL now=1;
while(top&&het[i]<=a[top])
now+=cnt[top],sum-=a[top]*cnt[top],top--;
cnt[++top]=now;
a[top]=het[i];
sum+=cnt[top]*a[top];
ans+=sum;
}
return ans;
}
int main()
{
scanf("%s",S+1);scanf("%s",T+1);
L1=strlen(S+1),L2=strlen(T+1);n=L1+L2+1;
S[L1+1]='z'+1;
for(re int i=1;i<=L2;i++) S[i+L1+1]=T[i];
tot+=SA();
for(re int i=L1+1;i<=n;i++) S[i]=0;
n=L1;tot-=SA();
for(re int i=1;i<=L2;i++) S[i]=T[i];
for(re int i=L2+1;i<=n;i++) S[i]=0;
n=L2;
tot-=SA();
printf("%lld\n",tot);
return 0;
}

【[HAOI2016]找相同字符】的更多相关文章

  1. BZOJ 4566: [Haoi2016]找相同字符 [后缀自动机]

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

  2. bzoj4566 / P3181 [HAOI2016]找相同字符

    P3181 [HAOI2016]找相同字符 后缀自动机 (正解应是广义后缀自动机) 并不会广义后缀自动机. 然鹅可以用普通的后缀自动机.   我们先引入一个问题:算出从一个串内取任意两个不重合子串完全 ...

  3. 【BZOJ4566】[HAOI2016]找相同字符

    [BZOJ4566][HAOI2016]找相同字符 题面 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 其中\(1\le ...

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

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

  5. 【BZOJ4566】[Haoi2016]找相同字符 后缀数组+单调栈

    [BZOJ4566][Haoi2016]找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同 ...

  6. bzoj 4566 [Haoi2016]找相同字符SA

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 128  Solved: 75[Submit][Status ...

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

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

  8. BZOJ_4566_[Haoi2016]找相同字符_后缀自动机

    BZOJ_4566_[Haoi2016]找相同字符_后缀自动机 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有 ...

  9. [HAOI2016] 找相同字符 - 后缀数组,单调栈

    [HAOI2016] 找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. \(n,m \l ...

  10. BZOJ4566 [Haoi2016]找相同字符【SAM】

    BZOJ4566 [Haoi2016]找相同字符 给定两个字符串\(s和t\),要求找出两个字符串中所有可以相互匹配的子串对的数量 首先考虑可以怎么做,我们可以枚举\(t\)串的前缀\(t'\),然后 ...

随机推荐

  1. my32_ error 1872 Slave failed to initialize relay log info structure from the repository

    重启了实例后,slave进程无法开启 Last_SQL_Errno: Last_SQL_Error: Slave failed to initialize relay log info structu ...

  2. 常用维护SQL-数据清理

    truncate某个库的表数据 show full processlist; select concat('truncate table ',table_schema,'.',table_name,' ...

  3. layui table合计但是未计算的解决

    在项目里table开启合计功能,但是并未进行数据计算,后来发现是field写错了的问题,上代码 for(var i = 0; i < that.checkboxAll.data.length; ...

  4. Angular4+NodeJs+MySQL 入门-04 接口调用类

    上一篇文章说一下,后台接口的创建,这篇说一下如果调用接口. 创建一个目录helpers 此目录下有三个文件分别是 ApiClient.ts.clientMiddleware.ts.Core.ts,前面 ...

  5. jQuery遍历祖先元素:parentsUntil

    Description: Get the ancestors of each element in the current set of matched elements, up to but not ...

  6. 查询指定tomcat应用的进程数

    假设应用名称为pear,查询指定tomcat应用pear的进程数: ps -ef |grep "/datong/tomcat-pear/" |grep -v tail | grep ...

  7. a标签的 onclick 和 href 哪个先执行?

    以下这种写法,onclick 事件先执行, href 属性下的动作后执行(页面跳转或 javascript 伪链接),如果不想执行 href 属性下的动作,onclick 需要返回 false. &l ...

  8. linux下快速安装python3.xx

    安装python3之前的准备工作: 当前环境是centos操作系统[已经安装了gcc++],在安装前需要安装zlib-devel包: yum install zlib-devel yum instal ...

  9. CMS API Overview - 翻译

    source: http://activemq.apache.org/cms/cms-api-overview.html 1. CMS是啥? C++版本的API,用于收发消息(JMS). 如果您已熟悉 ...

  10. IO流之转换流

    转换流 OutputStreamWriter类 查阅OutputStreamWriter的API介绍,OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流 ...