题目

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 
结果应该是3,因为:
  • strange set(“bba”) = {(1,4)}
  • bba的这两个后缀满足:strange set(“bba”) = {(1,4)}、strange set(“ba”) = {(1,4)}
  • 此外还有这个满足:strange set(“bbba”) = {(1,4)}
就是说还有包含整个字符串的可能满足。然后我想了想,画了画,又得出结论:
  • 这种情况的数量就是上下界的LCP长度减去查询串的长度!
另外要注意上界=下界的情况,还有特殊字符在这儿应该要互不相同。。
感觉这题好难描述= =就这样吧。。最后我终于AC了。。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 222222int 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;
}

转载于:https://www.cnblogs.com/WABoss/p/5778329.html

HDU5853 Jong Hyok and String(二分 + 后缀数组)相关推荐

  1. POJ - 3450 Corporate Identity(二分+后缀数组)

    题目链接:点击查看 题目大意:给出n个字符串,求出n个字符串中最长的公共子串,如果没有,输出IDENTITY LOST 题目分析:可以直接用二分+后缀数组来做,先将n个字符串连接起来,中间用一个不同的 ...

  2. HDU - 5008 Boring String Problem(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...

  3. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  4. POJ - 3261 Milk Patterns(二分+后缀数组)

    题目链接:点击查看 题目大意:给出一个字符串,以及一个k,现在求出现次数大于等于k次的最大可重叠子串的长度 题目分析:可以说是后缀数组的模板题目了吧..直接跑出height数组,因为height数组代 ...

  5. POJ - 1743 Musical Theme(二分+后缀数组+差分数组)

    题目链接:点击查看 题目大意:给出n个连续的数字组成的序列,现在要求出其中两个不重叠的字序列,满足两个子序列"相似",相似的定义是两个子序列当且仅当长度相等并且每一位的数字差都相等 ...

  6. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

  7. HDU 5008 Boring String Problem ( 后缀数组求本质不同第k大子串)

    Boring String Problem Zeronera题解 预处理sum数组记录不同字符串的个数,即sum[i] = n- sa[i] + 1 -height[i] + sum[i-1] (n为 ...

  8. POJ1226 Substrings(二分+后缀数组)

    题意:给n个字符串,求最长的子串,满足它或它的逆置出现在所有的n个字符串中. 把n个字符串及其它们的逆置拼接,中间用不同字符隔开,并记录suffix(i)是属于哪个字符串的: 跑后缀数组计算heigh ...

  9. zoj 1905 Power String(后缀数组)

     题意:给定一个字符串L,已知这个字符串是由某个字符串S 重复R 次而得到的,求R 的最大值. 做法比较简单,穷举字符串S 的长度k,然后判断是否满足.判断的时候, 先看字符串L 的长度能否被k ...

最新文章

  1. Python实现文本自动分类(朴素贝叶斯方法)
  2. 单片机 PWM输出 c
  3. pat 团体天梯赛 L2-012. 关于堆的判断
  4. 前端学习(1861)vue之电商管理系统电商系统之设置背景色并在中央绘制登录盒子
  5. 计算机组成原理节拍分为几种,计算机组成原理习题答案第七章
  6. 0x80070035找不到网络路径_ln -s 创建软链接时的路径问题
  7. VS2019配置opencv-4.5.2-vc14_vc15
  8. putty怎么更改为中文_Putty怎么样设置显示中文 设置Putty显示中文
  9. 专利与论文-6:《专利权利要求书》的撰写与注意事项
  10. 1024程序员节,云和恩墨送大礼啦
  11. Python-Bunch模式
  12. SpringBoot整合Tomcat中的组件
  13. Mac效率神器Alfred4以及常用Workflow【文末有福利】
  14. cubeIDE开发,在LCD显示摄像头抓取的图片数据
  15. 基于Flask快速搭建一个管理系统
  16. 2020年缴费基数调整
  17. 推荐一篇好文《佛教真像大家所认为的那样消极吗?》
  18. 【2016ACM/ICPC亚洲区大连站C】HDU - 5973 Game of Taking Stones 威佐夫博弈
  19. 微信小程序之数据处理
  20. Las Vegas 与回溯组合法解八皇后问题

热门文章

  1. 前端JavaScripts
  2. java面试题二十五 构造函数
  3. hadoop配置后无法通过主机名:50070访问,只能通过ip:50070访问
  4. C语言切割多层字符串(strtok_r strtok使用方法)
  5. 把十进制转为二进制到16进制
  6. python解决https私密连接警告信息
  7. sklearn综合示例9:分类问题的onehot与预测阈值调整
  8. 使用ResourceBundle加载properties文件
  9. Hadoop2.4.1入门实例:MaxTemperature
  10. java的守护线程与非守护线程