【BZOJ3879】SvT 后缀数组+单调栈
【BZOJ3879】SvT
Description
(我并不想告诉你题目名字是什么鬼)
有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].
现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.
Input
第一行两个正整数n,m,分别表示S的长度以及询问的次数.
接下来一行有一个字符串S.
接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:
首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.
Output
Sample Input
popoqqq
1 4
2 3 5
4 1 2 5 6
Sample Output
0
2
Hint
样例解释:
对于询问一,只有一个后缀”oqqq”,因此答案为0.
对于询问二,有两个后缀”poqqq”以及”qqq”,两个后缀之间的LCP为0,因此答案为0.
对于询问三,有四个后缀”popoqqq”,”opoqqq”,”qqq”,”qq”,其中只有”qqq”,”qq”两个后缀之间的LCP不为0,且长度为2,因此答案为2.
对于100%的测试数据,有S<=5*10^5,且Σt<=3*10^6.
特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.
题解:依旧是后缀数组+单调栈,跟差异那道题差不多,具体方法:
将给出的所有后缀按照rank排序,去重,然后用rmq查出相邻两个的LCP,现在问题转化成一个序列求两两间最小值,这又等价于对于序列中的每一个数,求它是哪些数对之间的最小值,这又等价于对于每一个数,求左边和右边第一个比它小的数,用单调栈轻松搞定。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 23333333333333333ll
using namespace std;
const int maxn=500010;
int r[maxn],ra[maxn],rb[maxn],st[maxn],h[maxn],sa[maxn],rank[maxn];
int q[maxn],t,ls[maxn],rs[maxn],f[maxn][20],Log[maxn],vis[maxn],v[maxn],s[maxn];
int n,m,Q;
typedef long long ll;
ll ans;
char str[maxn];
void build()
{
int i,j,k,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),x[sa[0]]=0,i=p=1;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=k=0;i<n-1;h[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
bool cmp(int a,int b)
{
return rank[a]<rank[b];
}
int query(int a,int b)
{
int k=Log[b-a+1];
return min(f[a][k],f[b-(1<<k)+1][k]);
}
int main()
{
scanf("%d%d%s",&n,&Q,str);
int i,j,a,b;
for(i=0;i<n;i++) r[i]=str[i]-'a'+1;
n++,m=27,build(),n--;
for(i=1;i<=n;i++) f[i][0]=h[i];
for(j=1;(1<<j)<n;j++)
for(i=1;i+(1<<j)-1<=n;i++)
f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(i=1;i<=Q;i++)
{
scanf("%d",&a);
for(j=1;j<=a;j++)
{
scanf("%d",&v[j]),v[j]--;
if(vis[v[j]]) j--,a--;
vis[v[j]]=1;
}
sort(v+1,v+a+1,cmp);
for(j=1;j<a;j++) s[j]=query(rank[v[j]]+1,rank[v[j+1]]);
s[0]=s[a]=-1,q[1]=0,t=1;
for(j=1;j<a;j++)
{
while(t&&s[q[t]]>s[j]) t--;
ls[j]=q[t],q[++t]=j;
}
t=1,q[1]=a;
for(j=a-1;j>0;j--)
{
while(t&&s[q[t]]>=s[j]) t--;
rs[j]=q[t],q[++t]=j;
}
ans=0;
for(j=1;j<a;j++) ans=(ans+(ll)(j-ls[j])*(rs[j]-j)*s[j])%mod;
printf("%lld\n",ans);
for(j=1;j<=a;j++) vis[v[j]]=0;
}
return 0;
}
【BZOJ3879】SvT 后缀数组+单调栈的更多相关文章
- BZOJ3879:SvT(后缀数组,单调栈,ST表)
Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...
- 【BZOJ-3238】差异 后缀数组 + 单调栈
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1561 Solved: 734[Submit][Status] ...
- BZOJ_3879_SvT_后缀数组+单调栈
BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- BZOJ3879: SvT【后缀数组+单调栈】
Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...
- poj 3415 Common Substrings 后缀数组+单调栈
题目链接 题意:求解两个字符串长度 大于等于k的所有相同子串对有多少个,子串可以相同,只要位置不同即可:两个字符串的长度不超过1e5; 如 s1 = "xx" 和 s2 = &qu ...
随机推荐
- iOS小知识点记录
1.创建视图的两种方法:用代码创建视图,创建XIB文件.如何决定使用哪种方法?参考法则:如果视图没有子视图,就用代码创建:如果有子视图,就通过XIB文件创建. 2.创建视图的时候,视图控制器会调用lo ...
- python selenium--常用函数1
新建实例driver = webdriver.Chrome() 1.通过标签属性Id查找元素 方法:find_element_by_id(element_id) 实例:driver.find_elem ...
- selenium2.0 --常用函数2
新建实例driver = webdriver.Chrome() 1.获取当前页面的Url函数 方法:current_url 实例: driver.current_url 2.获取元素坐标 方法:loc ...
- mysql导入慢
MySQL导出的SQL语句在导入时有可能会非常非常慢,经历过导入仅45万条记录,竟用了近3个小时.在导出时合理使用几个参数,可以大大加快导 入的速度. -e 使用包括几个VALUES列表的多行INSE ...
- unity Editor下自启动
[InitializeOnLoad] 加上这个特性,并且在静态构造函数里写上内容.即可在Unity启动的时候自启动这个Editor脚本
- Atitit.md5 实现原理
Atitit.md5 实现原理 1. 算法流程图2 2. MD5算法过程:2 2.1. 3. 处理分组数据3 3. MD5加密字符串实例5 4. Md5的历史7 4.1.1. MD27 4.1.2. ...
- Android Service演义
摘要: 本文基于Android 5.1代码,介绍了Android Service的运作机理.按理说,网上此类文章已经很多了,本不需我再赘述.但每个人理解技术的方式多少会有所不同,我多写一篇自己理解的s ...
- google_gflags使用
gflags是google开源的一个解析命令行参数的工具. 最简单的demo #include <iostream> #include <gflags/gflags.h> us ...
- 1.1 Application Fundamentals - 应用原理
Android应用是使用Java编程语言编写的.Android SDK工具把代码.资源和数据文件编译为一个Android包,这是一个有.apk后缀的压缩文件.一个单独的.apk文件里包含所有的代码,这 ...
- 基于ZK的分布式锁实现
import java.util.concurrent.TimeUnit; import org.apache.curator.framework.CuratorFramework; import o ...