HDU - 5769 Substring(后缀数组)
题目链接:点击查看
题目大意:给出一个字符串 s 和一个字符 ch,问字符串 s 中有多少个本质不同的子串包含字符 ch
题目分析:其实就是求本质不同的子串加了一点条件,对于每个sa[ i ],其本质不同的子串的个数原本为 len - sa[ i ] - height[ i ],现在需要比较一下这个值与包含sa[ i ]在内,之后首次出现字符 ch 的距离所组成的后缀长度,具体实现看代码就好了,其实用后缀自动机也可以做,因为每次添加一个字符后,会产生 len[ i ] - len[ fa[ i ] ] 个本质不同的字符串,且都是连续的,可以二分找到最长含有字符 ch 的位置,其实本质上和后缀数组的做法一样,只不过时间复杂度可能会小一点
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;char str[N];int sa[N]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[N],t2[N],c[N];int rk[N],height[N],len;int s[N];int nx[N];void build_sa(int s[],int n,int m)//n为添加0后的总长
{int i,j,p,*x=t1,*y=t2;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[i]=s[i]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1) {p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1,x[sa[0]]=0;for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;if(p>=n) break;m=p;}
}void get_height(int s[],int n)//n为添加0后的总长
{int i,j,k=0;for(i=0;i<=n;i++)rk[sa[i]]=i;for(i=0;i<n;i++) {if(k) k--;j=sa[rk[i]-1];while(s[i+k]==s[j+k]) k++;height[rk[i]]=k;}
}void solve(int base=128)
{build_sa(s,len+1,base);get_height(s,len);
}int main()
{
//#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
//#endif
// ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--){char ch[5];scanf("%s%s",ch,str);len=strlen(str);for(int i=0;i<len;i++)s[i]=str[i]-'a'+1;s[len]=0;solve(30);//跑后缀数组 nx[len]=nx[len+1]=inf;for(int i=len-1;i>=0;i--)//nx[i]:第i位后首次出现ch字符的位置 {nx[i]=nx[i+1];if(str[i]==ch[0])nx[i]=i;}LL ans=0;for(int i=1;i<=len;i++){if(nx[sa[i]]==inf)//后面没有符合条件的字符串了 continue;ans+=min(len-sa[i]-height[i],len-nx[sa[i]]);}printf("Case #%d: %lld\n",++kase,ans);}return 0;
}
HDU - 5769 Substring(后缀数组)相关推荐
- HDU 5769 Substring(后缀数组)
Substring Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total ...
- 牛客-139 I. Substring(后缀数组 or 后缀自动机)
牛客-139 I. Substring(后缀数组 or 后缀自动机) 题目链接 题意 一个由{a,b,c}\{a, b, c\}{a,b,c}组成的字符串SSS,求S子串的最大的集合,使得集合里的字符 ...
- Boring counting HDU - 3518 (后缀数组)
Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...
- HDU 5769 Substring
后缀数组. 然后按照排序完成之后的顺序,每个后缀统计贡献量. 统计第i个后缀的贡献的时候,如果这个后缀中没有X,贡献度为0. 有贡献的分3种情况考虑: 1.如果这个后缀height部分等于0(即与前一 ...
- POJ - 3693 Maximum repetition substring(后缀数组+RMQ)
题目链接:点击查看 题目大意:给出一个字符串,求出字符串中 重复次数最多的连续重复子串 ,如果有多个答案,输出字典序最小的 题目分析:又是一个模板题,这里放一个大佬的博客,讲的很清楚: https:/ ...
- POJ-3693 Maximum repetition substring 后缀数组
题目链接:http://poj.org/problem?id=3693 求字符串的重复次数最多的且字典序最小的字串. 很不错的题目.罗穗骞大牛论文的模板题,摘了Neo / Add ~0U>> ...
- hdu 5008 Boring String Problem(后缀数组+rmq)
题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...
- 后缀数组 --- HDU 3518 Boring counting
Boring counting Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3518 Mean: 给你一个字符串,求:至少出 ...
- HDU 6194 string string string :后缀数组+单调队列 | 后缀自动机
题意:给出一个字符串,求出出现了恰好k次的子串的个数. 题解:恰好k次 = 至少k次 - 至少k+1次.答案转化为求至少出现k次的子串个数统计.构造好后缀数组以及很重要的Height数组之后.用一个k ...
最新文章
- [NC15034]德玛西亚万岁
- os.chdir用法
- python语言程序设计2019版第二章课后答案-《python语言程序设计》_第二章编程题...
- 061_html字符实体
- git pull代码出现refusing to merge unrelated histories错误
- css盒模型和元素绘制
- 如何判断自己的编程水平
- CSS Center(居中专题)
- 正态总体样本的分布定理
- Photoshop cc 2019 破解教程
- 小程序下找地点、查路线、搜地铁,用这3个插件就够了!
- 电动汽车结构原理基础知识
- Lwip之PPP、PPPoE实现(一)
- Django CSRF Bypass 漏洞分析(CVE-2016-7401)
- VUE 物理返回键的处理
- SAP中复制创建采购申请的过程
- Input框内容改变触发事件,实现表格动态模糊查询
- MATLAB如何保存高质量大图
- 短信平台验证码的特点
- nodejs:fs (内置模块)读取和写入文件