[HAOI2016]找相同字符
题目描述
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。
输入输出格式
输入格式:
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
输出格式:
输出一个整数表示答案
输入输出样例
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]找相同字符的更多相关文章
- BZOJ 4566: [Haoi2016]找相同字符 [后缀自动机]
4566: [Haoi2016]找相同字符 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 275 Solved: 155[Submit][Statu ...
- bzoj4566 / P3181 [HAOI2016]找相同字符
P3181 [HAOI2016]找相同字符 后缀自动机 (正解应是广义后缀自动机) 并不会广义后缀自动机. 然鹅可以用普通的后缀自动机. 我们先引入一个问题:算出从一个串内取任意两个不重合子串完全 ...
- 【BZOJ4566】[HAOI2016]找相同字符
[BZOJ4566][HAOI2016]找相同字符 题面 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. 其中\(1\le ...
- [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp
4566: [Haoi2016]找相同字符 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1212 Solved: 694[Submit][Stat ...
- 【BZOJ4566】[Haoi2016]找相同字符 后缀数组+单调栈
[BZOJ4566][Haoi2016]找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同 ...
- bzoj 4566 [Haoi2016]找相同字符SA
4566: [Haoi2016]找相同字符 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 128 Solved: 75[Submit][Status ...
- [Bzoj4566][Haoi2016]找相同字符(广义后缀自动机)
4566: [Haoi2016]找相同字符 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 861 Solved: 495[Submit][Statu ...
- BZOJ_4566_[Haoi2016]找相同字符_后缀自动机
BZOJ_4566_[Haoi2016]找相同字符_后缀自动机 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有 ...
- [HAOI2016] 找相同字符 - 后缀数组,单调栈
[HAOI2016] 找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. \(n,m \l ...
- BZOJ4566 [Haoi2016]找相同字符【SAM】
BZOJ4566 [Haoi2016]找相同字符 给定两个字符串\(s和t\),要求找出两个字符串中所有可以相互匹配的子串对的数量 首先考虑可以怎么做,我们可以枚举\(t\)串的前缀\(t'\),然后 ...
随机推荐
- Linux 终端 Bash 常用快捷键介绍及经验
1. 最重要的自动补全 命令 解释 Tab 自动补全 不用多说,自动补全可以节省大量时间 2. 编辑跳转 命令 解释 Ctrl + A 跳转到当前行首 Ctrl + E 跳转到当前行末 Alt + F ...
- Beta 第四天
今天遇到的困难: 百度位置假死的问题研究发现并不是源于代码的问题,而是直接运行在主线程中会出现诸多问题 Fragment碎片刷新时总产生的固定位置的问题未果 今天完成的任务: 陈甘霖:修复了部分Bug ...
- Alpha第十天
Alpha第十天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...
- C语言字符数组作业
一.PTA实验作业 题目1:7-1 字符串转换成十进制整数 1. 本题PTA提交列表 2. 设计思路 3.代码截图 4.本题调试过程碰到问题及PTA提交列表情况说明. 1.一开始我没想到怎么判断正负的 ...
- 敏捷冲刺报告--Day5
敏捷冲刺报告--Day5 情况简介 GUI框架重写, 添加功能 任务进度 赵坤: 后端爬虫bug修复 李世钰: GUI编写 黄亦薇:更新sprint backlog.编写每日报告 王成科:召集小组成员 ...
- VMware虚拟机误删除vmdk文件后如何恢复?
故障描述: Dell R710系列服务器(用于VMware虚拟主机),Dell MD 3200系列存储(用于存放虚拟机文件),VMware ESXi 5.5版本,因意外断电,导致某台虚拟机不能正常启动 ...
- thinkphp中定义自己的函数
可以在前台和后台的公共文件夹中common.php中定义自己的函数,这样就可以在控制器中调用,而不需要调用对象了 /** * @name addvtorandp * @author 黄峰1664253 ...
- Mysql数据库mys和ora库的备份与恢复脚本
!/bin/bash Time=$(date +%Y%md%H%M%S) Back_dir="$HOME/mysqlback/${Time}" function Detect_u_ ...
- Spring Data Jpa简单了解
原文来源:http://www.cnblogs.com/xuyuanjia/p/5707681.html 以下是自己简单整理原有文章,其实就是在原来文章基础上化重点以及可能会有所删减的方式进行整理,需 ...
- 初学Java Web(1)——Web概述
已经很久没有更新博客了,过年忙着吃喝玩乐,就怠惰了一小下下?幸好这学期新开的课程都比较有趣--Java Web和Android.至少对于我自己来说,既充满挑战,又富有趣味. --[1.Web概述]-- ...