传送门
思路:
偶然翻到的一个题
苦思冥想算法之时……
旁边不(jing)会(tong)后缀数组的聪爷爷:这不是后缀数组吗?

赶紧来练一下遗忘的后缀数组(然后手打板子又错了,只能回到博客上重新翻一波以前写的)
设lenalen_a,lenblen_b为字符串a,b的长度
aia_i,bib_i分别表示字符串a,b的后缀[i..n][i..n]
那么答案就是
∑lenai=1∑lenbj=1lcp(ai,bj)\sum_{i=1}^{len_a}\sum_{j=1}^{len_b}lcp(a_i,b_j)
这个式子朴素做是O(n3)O(n^3)的
把两个串连一起然后再求后缀数组是可以做到O(n2)O(n^2),因为lcp是可以O(1)O(1)求的
但仍然不能使人满意
那怎么办?
之前写过类似的题,好像用的是单调栈
这次没这么做……
考虑把后缀按照rank排序后,height值是有大有小的(这不是废话吗)
比如我们想求得rank为[l,r][l,r]的后缀中对答案的贡献
我们可以求出[l+1,r]中最小的height所在的位置mid
也就是说heightmid<=heighti,i=l+1..rheight_{mid}
可以统计答案就是[l,mid-1]的a后缀个数×[mid,r]的b后缀个数+[l,mid-1]的b后缀个数×[mid,r]的a后缀个数,统计后缀个数可以用前缀和处理一下
然后可以再递归子问题[l,mid-1],[mid,r]了
相当于从小到大枚举height
复杂度O(n)O(n)
所以总复杂度就是后缀数组的建立与预处理ST表,即O(nlog2n)O(nlog_2n)
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
#define M 200005
using namespace std;
int la,lb,lc;
char a[M],b[M];
int c[M<<1],cnt[M<<1],rank[M<<1],sa[M<<1],id[M<<1],tmp[M<<1],height[M<<1],ST[19][M<<1],sum1[M<<1],sum2[M<<1];
void SA(int len,int up)
{int p=0,d=1,*rk=rank,*t=tmp;for (int i=0;i<len;++i) ++cnt[rk[i]=c[i]];for (int i=1;i<up;++i) cnt[i]+=cnt[i-1];for (int i=len-1;i>=0;--i) sa[--cnt[rk[i]]]=i;
    for (;;)
    {        for (int i=len-d;i<len;++i) id[p++]=i;
        for (int i=0;i<len;++i)
            if (sa[i]-d>=0) id[p++]=sa[i]-d;
        for (int i=0;i<up;++i) cnt[i]=0;
        for (int i=0;i<len;++i) ++cnt[t[i]=rk[id[i]]];
        for (int i=1;i<up;++i) cnt[i]+=cnt[i-1];
        for (int i=len-1;i>=0;--i) sa[--cnt[t[i]]]=id[i];
        swap(t,rk);
        p=1;
        rk[sa[0]]=0;
        for (int i=0;i<len-1;++i)
            if (sa[i]+d<len&&sa[i+1]+d<len&&t[sa[i]]==t[sa[i+1]]&&t[sa[i]+d]==t[sa[i+1]+d])
                rk[sa[i+1]]=p-1;
            else
                rk[sa[i+1]]=p++;
        if (p==len) return;
        d<<=1;up=p;p=0;
    }
}
void Height()
{
    for (int i=1;i<=lc;i++) rank[sa[i]]=i;
    int x,k=0;
    for (int i=0;i<lc;++i)
    {        k=max(k-1,0);
        x=sa[rank[i]-1];
        while (c[x+k]==c[i+k]) ++k;
        height[rank[i]]=k;
    }
}
LL solve(int l,int r)
{
    if (l>=r) return 0;
    int p=log2(r-l),mid;
    mid=height[ST[p][l+1]]>height[ST[p][r-(1<<p)+1]]?ST[p][r-(1<<p)+1]:ST[p][l+1];
    return solve(l,mid-1)+solve(mid,r)+((LL)(sum1[mid-1]-sum1[l-1])*(sum2[r]-sum2[mid-1])+(LL)(sum2[mid-1]-sum2[l-1])*(sum1[r]-sum1[mid-1]))*height[mid];
}
main()
{
    scanf("%s",a);scanf("%s",b);
    la=strlen(a);lb=strlen(b);
    for (int i=0;i<la;++i)
        c[i]=a[i]-'a'+1;
    c[la]='{'-'a'+1;
    for (int i=la+1;i<=lb+la;++i)
        c[i]=b[i-la-1]-'a'+1;
    SA(la+lb+2,29);
    lc=la+lb+1;
    Height();
    for (int i=1;i<=la+lb;++i)
        sum1[i]=sum1[i-1]+(sa[i]<la),
        sum2[i]=sum2[i-1]+(sa[i]>la);
    for (int i=1;i<=lc;++i) ST[0][i]=i;
    for (int i=1;1<<i<=lc;++i)
        for (int j=1;(1<<i)+j-1<=lc;++j)
            ST[i][j]=(height[ST[i-1][j]]>height[ST[i-1][j+(1<<i-1)]]?ST[i-1][j+(1<<i-1)]:ST[i-1][j]);
    printf("%lld",solve(1,lc-1));
}

【BZOJ4566】找相同字符,后缀数组相关推荐

  1. [bzoj4566][HAOI2016]找相同字符(后缀数组)

    题目 传送门 题解 这里:把两个串用一个很大的字符连接起来,求一个后缀数组. 考虑怎样暴力的算答案. 在 rank  r a n k rank数组中从前往后枚举起点,对于每个枚举的起点,都暴力的往后扫 ...

  2. 【HAOI2016/BZOJ4566】找相同字符 后缀数组+单调栈

    原题走这里 鉴于我实在不是很懂单调栈和单调队列这一系列东西,所以我决定稍微具体讲一下单调栈. 恩,本题实质上就是求两个字符串的公共子串数,其中只要出现位置不同,就算是不同的子串. 处理多个字符串的经典 ...

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

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

  4. 【bzoj4566】找相同字符 后缀自动机

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4566 [题解] 我们还是先把A串建成SAM,然后让B串在SAM上跑 因为相同子串数=不同长 ...

  5. [BZOJ4566][HAOI2016]找相同字符 后缀自动机

    题目要求的就是B的每个字串在A中的出现次数之和. 我们考虑先建出A串的SAM,每个点所代表的串的个数就是 |Righti|∗(Maxi−Maxfai) |Right_i|*(Max_i-Max_{fa ...

  6. 【BZOJ4566】找相同字符(后缀数组)

    题面 BZOJ 题解 后缀数组的做法,应该不是很难想 首先看到两个不同的串,当然是接在一起求 SA,height SA,height 那么,考虑一下暴力 在两个串各枚举一个后缀,他们的 lcp lcp ...

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

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

  8. 【BZOJ1031】[JSOI2007]字符加密Cipher 后缀数组

    [BZOJ1031][JSOI2007]字符加密Cipher Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的 ...

  9. 长字符串匹配(BWT编码、后缀数组、倍增算法、FM索引)

    用 O(m) 时间复杂度找出一个长度为 m 的短字符串在一个长度为 n 的长字符串中的精确匹配(n>>m),限制长短字符串仅由 A.C.G.T 这四种字符组成. 输入:长短字符串 输出:短 ...

最新文章

  1. java 必须存在默认构造器_Java默认构造方法在字节码的实现
  2. 【EventBus】发布-订阅模式 ( EventBus 组成模块 | 观察者模式 )
  3. html5 Canvas画图教程(5)—canvas里画曲线之arc方法
  4. 学习3D游戏开发进阶之路
  5. 方立勋_30天掌握JavaWeb_Servlet
  6. mysql综合查询索引优化_MySQL数据库SQL优化之确定问题使用索引提高查询效率
  7. c#winform演练 ktv项目 MediaPlay控件的暂停播放与停止
  8. File类的用法总结,及文件过滤器的介绍。
  9. javascript的对象内容对比
  10. 数学建模学习笔记:层次分析法
  11. flutter中的常见色值设置
  12. java 如何获取当前时间到夜晚12点的毫秒差值
  13. 1.6python网络爬虫--读取和处理纯文本格式(CSV,PDF,docx)
  14. js的tree转数组
  15. 中国不是没有根服务器吗?《流浪地球2》的根服务器怎么在北京?
  16. word html密码,Word文档加密打不开怎么办?Word解除密码的三种解决办法
  17. 【有利可图网】PS教程:利用PS分分钟将照片变成中国风古画效果
  18. 计算机错误678,宽带连接错误678,教您宽带连接错误678怎么解决
  19. 亚马逊、Lazada、shopee、eBay、wish、速卖通、沃尔玛、独立站、美客多、敦煌、阿里国际、mercari、newegg、Tiktok测评(补单)如何规避风控?应该选择哪些站点?
  20. oracle统计合格率,Oracle命准率及优化配置

热门文章

  1. 【nodejs原理源码赏析(3)】欣赏手术级的原型链加工艺术
  2. scrollbarStyle属性
  3. html主要的骨架结构
  4. R语言学习笔记(三)多元数据的数据特征、相关分析与图形表示
  5. WORD如何缩小编号与文本之间的距离?
  6. python处理金融数据_python-金融数据处理demo
  7. day22 java的枚举
  8. ajax struts 返回html,Struts2+ajax 异步请求,向前段返回字符串
  9. python mysql s_Python-MySQL
  10. 编程fi什么意思_盲人程序员如何编程?全靠每分钟450个单词