题目描述

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

输入输出格式

输入格式:

两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母

输出格式:

输出一个整数表示答案

输入输出样例

输入样例#1:
复制

aabb
bbaa
输出样例#1: 复制

10
将两串合并,中间加一个分隔符
先求出后缀数组和LCP的height数组
要求的就是后缀数组中不属于同一串的后缀的LCP
对于每一个(l,r)找到最小值位置minpos
在两边找来自两个不同串后缀数,分两种情况统计
然后分两边(l,minpos-1),(minpos,r)
用线段树维护
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long lol;
struct Seg
{
lol cnt[];
int x,pos;
}t[];
struct Data
{
int l,r;
};
int SA[],c[],rank[],x[],y[],len1,len2,n,m,s[];
char s1[],s2[];
queue<Data>Q;
lol ans,h[];
void build(int rt,int l,int r)
{
if (l==r)
{
if (SA[l]<len1) t[rt].cnt[]=;
if (SA[l]>len1) t[rt].cnt[]=;
t[rt].x=h[l];
t[rt].pos=l;
return;
}
int mid=(l+r)>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
t[rt].cnt[]=t[rt<<].cnt[]+t[rt<<|].cnt[];
t[rt].cnt[]=t[rt<<].cnt[]+t[rt<<|].cnt[];
if (t[rt<<].x<=t[rt<<|].x)
{
t[rt].pos=t[rt<<].pos;
t[rt].x=t[rt<<].x;
}
else
{
t[rt].pos=t[rt<<|].pos;
t[rt].x=t[rt<<|].x;
}
}
lol query_cnt(int rt,int l,int r,int L,int R,int x)
{
if (l>=L&&r<=R)
{
return t[rt].cnt[x];
}
int mid=(l+r)>>;
lol s=;
if (L<=mid) s+=query_cnt(rt<<,l,mid,L,R,x);
if (R>mid) s+=query_cnt(rt<<|,mid+,r,L,R,x);
return s;
}
int query_min(int rt,int l,int r,int L,int R)
{
if (l>=L&&r<=R)
{
return t[rt].pos;
}
int mid=(l+r)>>,s1=-,s2=-;
if (L<=mid) s1=query_min(rt<<,l,mid,L,R);
if (R>mid) s2=query_min(rt<<|,mid+,r,L,R);
if (s2==-) return s1;
if (s1==-) return s2;
if (h[s2]>=h[s1]) return s1;
return s2;
}
void radix_sort()
{int i;
for (i=;i<m;i++)
c[i]=;
for (i=;i<n;i++)
c[x[y[i]]]++;
for (i=;i<m;i++)
c[i]+=c[i-];
for (i=n-;i>=;i--)
SA[--c[x[y[i]]]]=y[i];
}
void build_SA()
{int i,j,k,p;
for (i=;i<n;i++)
x[i]=s[i],y[i]=i;
m=;
radix_sort();
for (k=;k<=n;k<<=)
{
p=;
for (i=n-k;i<n;i++)
y[p++]=i;
for (i=;i<n;i++)
if (SA[i]>=k) y[p++]=SA[i]-k;
radix_sort();
p=;
swap(x,y);
x[SA[]]=;
for (i=;i<n;i++)
x[SA[i]]=((y[SA[i]]==y[SA[i-]])&&((SA[i]+k<n?y[SA[i]+k]:-)==(SA[i-]+k<n?y[SA[i-]+k]:-)))?p-:p++;
if (p>=n) break;
m=p;
}
for (i=;i<n;i++)
rank[SA[i]]=i;
int L=;
for (i=;i<n;i++)
if (rank[i]>)
{
if (L>) L--;
j=SA[rank[i]-];
while (i+L<n&&j+L<n&&(s[i+L]==s[j+L])) L++;
h[rank[i]]=L;
}
}
int main()
{int i;
cin>>s1>>s2;
len1=strlen(s1),len2=strlen(s2);
for (i=;i<len1;i++)
s[i]=(int)s1[i];
s[len1]=(int)'#';
for (i=;i<len2;i++)
s[i+len1+]=(int)s2[i];
n=len1+len2+;
build_SA();
build(,,n-);
Q.push((Data){,n-});
while (Q.empty()==)
{
Data u=Q.front();
Q.pop();
int l=u.l,r=u.r;
int minpos=query_min(,,n-,l+,r);
//cout<<l<<' '<<r<<' '<<h[minpos]<<endl;
if (l<minpos-) Q.push((Data){l,minpos-});
if (minpos<r) Q.push((Data){minpos,r});
ans+=query_cnt(,,n-,l,minpos-,)*query_cnt(,,n-,minpos,r,)*h[minpos];
ans+=query_cnt(,,n-,l,minpos-,)*query_cnt(,,n-,minpos,r,)*h[minpos];
}
cout<<ans;
}

[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. java-JProfiler(一)-安装以及简介

    一.下载 下载http://www.ej-technologies.com/download/jprofiler/files 目前网上有9.2版本的使用方式,10.暂时还无法完美使用 可以下载zip包 ...

  2. Week04-面向对象设计与继承

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 is a关系 覆盖 Object 超级父类 继承 抽象类 多态 重载 static super private public p ...

  3. 那些在django开发中遇到的坑

    1. 关于csrf错误 CSRF(Cross-site request forgery)跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或 ...

  4. python 二叉堆

    BinaryHeap() 创建一个新的,空的二叉堆. insert(k) 向堆添加一个新项. findMin() 返回具有最小键值的项,并将项留在堆中. delMin() 返回具有最小键值的项,从堆中 ...

  5. django的模板(二)

    模板(二) 实验简介 本节继续介绍模板的常用标签,for.if.ifequal和注释标签. 一.基本的模板标签和过滤器 1. 标签 if/else {% if %} 标签检查(evaluate)一个变 ...

  6. Twisted UDP编程技术

    实战演练1:普通UDP UDP是一种无连接对等通信协议,没有服务器和客户端概念,通信的任何一方均可通过通信原语直接和其他方通信 1.相对于TCP,UDP编程只需定义DatagramProtocol子类 ...

  7. Environment.getExternalStorageDirectory()

    Environment.getExternalStorageDirectory()得到的是storage/emulated/0

  8. python 3.x 爬虫基础---常用第三方库(requests,BeautifulSoup4,selenium,lxml )

    python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 python 3.x 爬虫基础---常用第三方库 ...

  9. JAVA_SE基础——1.JDK&JRE下载及安装

    这是我学了JAVA来写的第一篇博客: 我首先是在传智播客领了张.毕向东老师的免费JAVA学习光盘来学习! 下面我来教大家安装使用JAVA时候必备的JDK 1.首先上甲骨文公司的官方网站下载JDK的安装 ...

  10. 外网访问本地服务器下的web应用

    让本地服务器可以在外网访问的方式有很多,介绍其中一种: 由于本人是在自己电脑上装了一个虚拟机, 测试环境为:虚拟机作为服务器,服务器中装了一个禅道,虚拟机IP192.168.2.221,本人通过tpl ...