题目描述

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

输入输出格式

输入格式:

两行,两个字符串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. C语言程序设计(基础)- 第14、15周作业

    从本周开始,将作业标记为学校自然周,而不是开课的周数. 要求一(25经验值) 完成14.15周的所有PTA中题目集. 注意1:一周两次pta作业,包括四次. 要求二(50经验值) 博客的具体书写内容和 ...

  2. bug终结者 团队作业第一周

    bug终结者 团队作业第一周 小组组员及人员分工 小组成员 组长: 20162323 周楠 组员: 20162302 杨京典 20162322 朱娅霖 20162327 王旌含 20162328 蔡文 ...

  3. bug终结者 团队作业第三周

    bug终结者 团队作业第三周 团队展示 队名 bug终结者 队员风采: 杨京典 20162302 风格:先构建框架,在一 一实现,在实现的过程中不断测试和修改. 擅长的技术:拆分问题,使用相对简单的思 ...

  4. 201621123040《Java程序设计》第十一周学习总结

    1.本周学习总结 1.1以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2.书面作业 2.1源代码阅读:多线程程序BounceThread 2.1.1BallRunnable类有什么用?为什 ...

  5. 高校学生征信系统Postmortem结果

    Postmortem结果 设想和目标 1 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件需要解决的问题是当前高校学生征信系统建设薄弱的问题,我们试图建立 ...

  6. cpp常用函数总结

    //sprintf sprintf(temp_str_result, "%lf", temp_double); result = temp_str_result; (*begin) ...

  7. 基础篇 - SQL 的约束

    基础篇 - SQL 的约束       约束 一.实验简介 约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性.唯一性.本节实验将在实践操作中熟悉 MySQL 中的几种约束. 二 ...

  8. Python内置函数(44)——len

    英文文档: len(s) Return the length (the number of items) of an object. The argument may be a sequence (s ...

  9. java中类的三大特征之多态

    Java 多态 同一种事物由于条件不同,展示出不同的结果,叫做多态. 父类的引用类型,由于使用不同的子类对象实例,而执行不同的操作. 多态存在的三个必要条件 1. 子类继承父类: 2. 子类重写父类方 ...

  10. WPF 自定义ItemsControl/ListBox/ListView控件样式

    一.前言 ItemsControl.ListBox.ListView这三种控件在WPF中都可作为列表信息展示控件.我们可以通过修改这三个控件的样式来展示我们的列表信息. 既然都是展示列表信息的控件,那 ...