HDU5853 Jong Hyok and String(二分 + 后缀数组)
题目
Source
http://acm.hdu.edu.cn/showproblem.php?pid=5853
Description
Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We called strange set(s) = {(i, j) | s occurs in Pi and j is the position of its last character in the current occurence}. And for ith question, you must answer the number of different strings t which satisfies strange set(Qi) = strange set(t) and t is a substring of at least one of the given n strings.
Input
First line contains T, a number of test cases.
For each test cases, there two numbers n, m and then there are n strings Pi and m strings Qj.(i = 1…n, j = 1…m)
1 <= T <= 10
1 <= n <= 100000
1 <= m<= 500000
1 <=|Pi|<=100000
1 <=|Qi|<=100000
∑ni=1|Pi|≤100000
File size is less than 3.5 megabytes.
Output
For each test case, first line contains a line “Case #x:”, x is the number of the case.
For each question, you should print one integer in one line.
Sample Input
1
2 2
aba
ab
a
ab
Sample Output
Case #1:
1
2
分析
题目大概说给若干的字符串pi,然后若干个询问,询问pi内有多少个不同子串与给定的询问字符串的strange set相同。一个字符串的strange set是一个二元组(i,j)的集合,表示该字符串在pi中出现且最后一个字符在pi中的位置j。
这题比赛时和队友讨论了挺久的。
首先想到的是,与查询串的strange set相同一定是查询串的后缀(其实不止是这样= =)。而查询串后缀的strange set不与查询串相同的情况是这个后缀在pi中被匹配了,但在那个位置查询串没被匹配。
然后队友考虑到通过把串反转,将后缀转化成前缀。
接下去,看到Σ|pi|<=100000,所以开始往后缀数组上面想。自然,那些pi要反转(这时考虑的是前缀了),然后拼接起来,中间用特殊字符隔开。
而求得其各个后缀排序后,对于任何一个模式串是能通过二分去查找到它所在匹配位置。然后就开始考虑对于查询串的各个前缀,去通过二分其位置的上下界求得有多少个与其匹配,然后再与查询串匹配次数对比,如果相等说明该前缀是可行的。
不过时间复杂度显然不行。后面我想到如果前缀x不行,那么前缀x-1也一定不行,然后慢慢地得出了这个结论——
- 对于各个查询串,通过两次二分,找到它匹配的上界upp和下界low(upp<=low。。),那么结果就是|查询串|-max(LCP(upp,upp-1),LCP(low,low+1))!
我们验证了时间复杂度,是所有查询串总长*logΣ|pi|,所有查询串总长Clarification说到200W左右,那样大概是可以一试的。于是就写了,不过WA= =二分改了改,然后什么什么。。比赛结束也没搞出来。
其实,一开始逻辑就有漏洞了。。【与查询串的strange set相同一定是查询串的后缀(其实不止是这样= =)】,还有一种情况!
比如这个数据:
1 1
bbbaa
bba
- strange set(“bba”) = {(1,4)}
- bba的这两个后缀满足:strange set(“bba”) = {(1,4)}、strange set(“ba”) = {(1,4)}
- 此外还有这个满足:strange set(“bbba”) = {(1,4)}
- 这种情况的数量就是上下界的LCP长度减去查询串的长度!
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 222222 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l];
}
int sa[MAXN],rnk[MAXN],height[MAXN];
void SA(int *r,int n,int m){
int *x=wa,*y=wb; for(int i=0; i<m; ++i) ws[i]=0;
for(int i=0; i<n; ++i) ++ws[x[i]=r[i]];
for(int i=1; i<m; ++i) ws[i]+=ws[i-1];
for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; int p=1;
for(int j=1; p<n; j<<=1,m=p){
p=0;
for(int i=n-j; i<n; ++i) y[p++]=i;
for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j;
for(int i=0; i<n; ++i) wv[i]=x[y[i]];
for(int i=0; i<m; ++i) ws[i]=0;
for(int i=0; i<n; ++i) ++ws[wv[i]];
for(int i=1; i<m; ++i) ws[i]+=ws[i-1];
for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i];
swap(x,y); x[sa[0]]=0; p=1;
for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
} for(int i=1; i<n; ++i) rnk[sa[i]]=i;
int k=0;
for(int i=0; i<n-1; height[rnk[i++]]=k){
if(k) --k;
for(int j=sa[rnk[i]-1]; r[i+k]==r[j+k]; ++k);
}
} int st[18][MAXN];
void ST(int *a,int n){
for(int i=1; i<=n; ++i) st[0][i]=a[i];
for(int i=1; i<18; ++i){
for(int j=1; j<=n; ++j){
if(j+(1<<i)>n) break;
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
}
}
int rmq(int a,int b){
if(a>b) swap(a,b);
int k=(int)(log2(b-a+1)+1e-6);
return min(st[k][a],st[k][b-(1<<k)+1]);
} char str[MAXN];
int an,a[MAXN],b[MAXN],bn;
int len[MAXN]; int cmp(int k){
int i;
for(i=0; i+k<an && i<bn; ++i){
if(a[i+k]>b[i]) return 1;
else if(a[i+k]<b[i]) return -1;
}
if(i!=bn) return -1;
return 0;
} int main(){
int t,n,m;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
scanf("%d%d",&n,&m);
an=0;
for(int i=0; i<n; ++i){
scanf("%s",str);
for(int j=strlen(str)-1; j>=0; --j){
len[an]=j+1;
a[an++]=str[j]-'a'+1;
}
a[an++]=28+i;
}
a[an++]=0;
SA(a,an,28+n);
ST(height,an-1);
printf("Case #%d:\n",cse);
while(m--){
scanf("%s",str);
bn=0;
for(int j=strlen(str)-1; j>=0; --j){
b[bn++]=str[j]-'a'+1;
} int l=1,r=an-1;
int upp=-1;
while(l<=r){
int mid=l+r>>1;
int tmp=cmp(sa[mid]);
if(tmp==0){
upp=mid;
r=mid-1;
}else if(tmp>0) r=mid-1;
else if(tmp<0) l=mid+1;
}
if(upp==-1){
printf("%d\n",0);
continue;
}
l=1,r=an-1;
int low=-1;
while(l<=r){
int mid=l+r>>1;
int tmp=cmp(sa[mid]);
if(tmp==0){
low=mid;
l=mid+1;
}else if(tmp>0) r=mid-1;
else if(tmp<0) l=mid+1;
}
int tmp=0;
if(upp!=1){
tmp=max(tmp,height[upp]);
}
if(low!=an-1){
tmp=max(tmp,height[low+1]);
}
if(upp==low) printf("%d\n",bn-tmp+len[sa[upp]]-bn);
else printf("%d\n",bn-tmp+rmq(upp+1,low)-bn);
}
}
return 0;
}
HDU5853 Jong Hyok and String(二分 + 后缀数组)的更多相关文章
- 【HDU 5030】Rabbit's String (二分+后缀数组)
Rabbit's String Problem Description Long long ago, there lived a lot of rabbits in the forest. One d ...
- BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)
求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...
- HDU4080 Stammering Aliens(二分 + 后缀数组)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...
- 140. 后缀数组(hash + 二分 / 后缀数组)
题目链接 : https://www.acwing.com/problem/content/description/142/ Hash + 二分 #include <bits/stdc++.h& ...
- UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)
题意:找一个出现了m次的最长子串,以及这时的最右的位置. hash的话代码还是比较好写的,,但是时间比SA多很多.. #include <stdio.h> #include <alg ...
- POJ1743 Musical Theme(二分+后缀数组)
题目大概是给n个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 这题是传说中楼教主男人八题之一,虽然已经是用后缀数组解决不可重叠最 ...
- HDU 6194 string string string(后缀数组+RMQ)
string string string Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- POJ1226 Substrings(二分+后缀数组)
题意:给n个字符串,求最长的子串,满足它或它的逆置出现在所有的n个字符串中. 把n个字符串及其它们的逆置拼接,中间用不同字符隔开,并记录suffix(i)是属于哪个字符串的: 跑后缀数组计算heigh ...
- POJ3294 Life Forms(二分+后缀数组)
给n个字符串,求最长的多于n/2个字符串的公共子串. 依然是二分判定+height分组. 把这n个字符串连接,中间用不同字符隔开,跑后缀数组计算出height: 二分要求的子串长度,判断是否满足:he ...
随机推荐
- Python--常见问题解决方案
1.如何支持中文,在第一行加上编码格式的支持: # coding=gbk +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...
- iOS - 二维码扫描和应用跳转
序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦, ...
- 1.1 STL 概述
综述 STL = Standard Template Library,标准模板库,惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov.Meng Lee和David R M ...
- hdu 2159 FATE
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路:二维完全背包,状态转移方程为: f[j][l]=max(f[j][l],f[j-b[i]] ...
- php 用户登录验证
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- HTML5 – 1.基础
新网页结构 1.<header> 定义了文档的头部区域 2.<nav>标签定义导航链接的部分. 3.<article>定义页面独立的内容区域. 4.<sect ...
- 无废话Android之listview入门,自定义的数据适配器、采用layoutInflater打气筒创建一个view对象、常用数据适配器ArrayAdapter、SimpleAdapter、使用ContentProvider(内容提供者)共享数据、短信的备份、插入一条记录到系统短信应用(3)
1.listview入门,自定义的数据适配器 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/and ...
- Linux进程状态 ( Linux Process State Codes)
进程状态代码及说明: STATE代码 说明 D 不可中断的睡眠. 通常是处于I/O之中. R 运行中/可运行. 正处于运行队列中. S 可中断的睡眠. 等待某事件发生. T 已停止. 可能是因为she ...
- Vue#Class 与 Style 绑定
绑定HTMLCLASS 在我没看这之前,我觉得要写绑定class ,应该像绑定数据一样这么写 class ={{class-a}} 看官方教程时,不推荐这么写,推荐这样 v-bind:class=&q ...
- hdu 3183(贪心)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 思路:比较前后两个相邻的字符,如果前面一个字符大于后面一个字符,就把它去掉. #include ...