【BZOJ3277/3473】串/字符串 后缀数组+二分+RMQ+双指针
【BZOJ3277】串
Description
Input
Output
Sample Input
Sample Output
HINT
对于100%的数据,n,k,l<=100000
题解:需要的用的方法好像有点多,但是也比我一开始自己yy的要少,我一开始yy的是后缀数组+主席树+线段树(233)
首先用到这样一个结论,就是如果第i个后缀有x个前缀能被k个串包含,那么第i+1个后缀至少有x-1个前缀能被k个串包含(与height数组的求法类似~)
那么我们先预处理这样一个东西,ls[i]代表从最大的j使得[j,i]中包含k个串([j,i]我指的是height数组上的一段区间)。这个可以用双指针法直接搞。
然后我们仿照height数组的求法,假设后缀i-1有x个合法前缀,那么到第i个后缀的时候我们就从x开始向上枚举,用二分+ST表找出它左(右)边第一个height比它小的位置,再用ls判断一下这段区间是否包含k个串就行了,时间复杂度O(nlogn)。
#include <cstdio>
#include <iostream>
#include <cstring>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
int num,n,k,len,m,t,sum;
int r[maxn],sa[maxn],st[maxn],ra[maxn],rb[maxn],h[maxn],rank[maxn],bel[maxn],s[maxn],last[maxn];
char str[maxn];
int f[maxn][20],Log[maxn],ls[maxn],v[maxn];
long long ans[maxn];
void work()
{
int i,j,p,*x=ra,*y=rb;
for(i=0;i<n;i++) st[x[i]=r[i]]++;
for(i=1;i<m;i++) st[i]+=st[i-1];
for(i=n-1;i>=0;i--) sa[--st[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p)
{
for(p=0,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++) st[i]=0;
for(i=0;i<n;i++) st[x[y[i]]]++;
for(i=1;i<m;i++) st[i]+=st[i-1];
for(i=n-1;i>=0;i--) sa[--st[x[y[i]]]]=y[i];
for(swap(x,y),i=p=1,x[sa[0]]=0;i<n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;
}
for(i=1;i<n;i++) rank[sa[i]]=i;
for(i=p=0;i<n-1;h[rank[i++]]=p)
for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
}
int query(int a,int b)
{
if(a>b) return 1<<30;
int c=Log[b-a+1];
return min(f[a][c],f[b-(1<<c)+1][c]);
}
int check(int x,int y)
{
int L=x,R=n,mid;
while(L<R)
{
mid=L+R>>1;
if(query(x+1,mid)>=y) L=mid+1;
else R=mid;
}
if(query(ls[L-1]+1,L-1)>=y) return 1;
return 0;
}
int main()
{
scanf("%d%d",&num,&k);
int i,j,a,p;
for(i=1;i<=num;i++)
{
scanf("%s",str),a=strlen(str);
for(j=0;j<a;j++) bel[n]=i,r[n++]=str[j]-'a'+num;
last[i]=n,r[n++]=num-i;
}
m=26+num;
work();
for(i=num;i<n;i++) f[i][0]=h[i];
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<n;j++)
for(i=num;i+(1<<j)-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
for(i=num;i<n&&sum<k;i++) sum+=!s[bel[sa[i]]],s[bel[sa[i]]]++;
ls[i-1]=num;
for(j=num;i<n;i++)
{
sum+=!s[bel[sa[i]]],s[bel[sa[i]]]++;
for(;j<=i&&sum>=k;j++) s[bel[sa[j]]]--,sum-=!s[bel[sa[j]]];
ls[i]=j-1;
}
for(i=p=0;i<n;i++)
{
if(!bel[i]) continue;
for(p?p--:0;p<last[bel[i]]-i&&check(rank[i],p+1);p++);
ans[bel[i]]+=p;
}
for(i=1;i<num;i++) printf("%lld ",ans[i]);
printf("%lld",ans[num]);
return 0;
}
【BZOJ3277/3473】串/字符串 后缀数组+二分+RMQ+双指针的更多相关文章
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单 ...
- 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)
3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串 ...
- 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ
[BZOJ4556][Tjoi2016&Heoi2016]字符串 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一 ...
- 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 657 Solved: 274[Su ...
- BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )
全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...
- BZOJ3277 串(后缀数组+二分答案+主席树)
因为不会SAM,考虑SA.将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法. 对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了.这是 ...
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
[BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...
- HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))
题意 大概就是给你一个串,对于每个\(i\),在\([1,i-1]\)中找到一个\(j\),使得\(lcp(i,j)\)最长,若有多个最大\(j\)选最小,求\(j\)和这个\(lcp\)长度 思路 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
随机推荐
- Stack Exchange 的架构
近日,Stack Exchange系统管理员blog上发布了一篇关于Stack Exchange的架构一瞥,其包括了Stack Overflow, Server Fault 和 Super User的 ...
- c# 用OpenXmL读取.xlsx格式的Excel文件 返回DataTable
1.须要引用的dll : DocumentFormat.OpenXml.dll ---须要安装一下OpenXml再引用 WindowsBase ---直接在项目里加入引用 2.方法: /// & ...
- 后缀数组suffix array
倍增算法,时间复杂度O(nlogn) sa从小到大保存相对大小的下标 理解LSD,x数组,sa数组 char s[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn ...
- iOS即时通讯输入框随字数自适应高度
代码地址如下:http://www.demodashi.com/demo/13210.html 前言 本人最近在研究socket与聊天界面的UI,在写聊天界面UI的时候是模仿微信的界面其中的文字输入框 ...
- SSH框架中POJO层, Dao层,Service层, Action层的功能理解
pojo层就是对应的数据库表的实体类(如User类). dao层,一般可以再分为***dao接口和***daoImpl实现类,如userDao接口和userDaoImpl实现类,接口负责定义数据库cu ...
- C#绑定事件时使用匿名函数
当使用一些临时的函数 可以预知这些函数基本不会被复用时 可以使用匿名函数简化代码 public static void startCoupons() { //绑定一些事件 userGetCoupon ...
- MvcPager帮助文档 - MvcAjaxOptions 类
表示用于 MvcPager 在 Ajax 分页模式下的选项设置,该类继承自 AjaxOptions. 公共属性: 名称 说明 默认值 AllowCache 获取或设置一个值,该值指示是否在Ajax分页 ...
- C++之栈、队列基本用法
1.C++栈的基本用法: #include<stack> (1)push():向栈内压入一个成员: (2)pop():栈顶弹出一个成员: (3)empty():栈为空返回true,否则返回 ...
- Creating Dialogbased Windows Application (4) / 创建基于对话框的Windows应用程序(四)Edit Control、Combo Box的应用、Unicode转ANSI、Open File Dialog、文件读取、可变参数、文本框自动滚动 / VC++, Windows
创建基于对话框的Windows应用程序(四)—— Edit Control.Combo Box的应用.Unicode转ANSI.Open File Dialog.文件读取.可变参数.自动滚动 之前的介 ...
- Servlet3.0: 简介AsyncContext
每个请求来到Web容器,Web容器会为其分配一条执行绪来专门负责该请求,直到回应完成前,该执行绪都不会被释放回容器. 执行绪会耗用系统资源,若有些请求需要长时间处理(例如长时间运算.等待某个资源),就 ...