Description

Solution

当 \(k\) 值较小时,发现询问串比较多,串长比较小

然后对 \(Q\) 个询问区间离线跑莫队,一次考虑每一个区间的贡献

假设一个区间 \([i,j]\) 出现的次数是 \(c[i][j]\),然后 \(O(k^2)\) 求出每一个区间的贡献,乘上 \(c[i][j]\) 就是答案

当 \(k\) 值较大时,询问次数比较少,串长比较大

考虑与询问次数有关的做法

对于每一个询问,预处理出 \(w\) 的每一个前缀在 \(S\) 的 \(SAM\) 中匹配到的位置和匹配的长度

右端点固定时,左端点移动形成的串就是这个右端点对应的前缀的后缀,每一次跳父亲就可以跳到

倍增到合法长度的节点即可

显然 \(k\) 取 \(\sqrt{10^5}\) 时最优

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>void gi(T &x){
int f;char c;
for (f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for (x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=2e5+10,M=320,B=20;
int n,m,Q,K,ch[N][26],fa[N],cur=1,cnt=1,len[N],sz[N],sa[N],c[N],g[N];
char s[N];
inline void ins(int c){
int p=cur;cur=++cnt;len[cur]=len[p]+1;
for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=ch[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int nt=++cnt;len[nt]=len[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[q]));
fa[nt]=fa[q];fa[q]=fa[cur]=nt;
for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
}
}sz[cur]=1;
}
inline void priwork(){
for(int i=1;i<=cnt;i++)c[len[i]]++;
for(int i=1;i<=n;i++)c[i]+=c[i-1];
for(int i=cnt;i>=1;i--)sa[c[len[i]]--]=i;
for(int i=cnt;i>=1;i--)sz[fa[sa[i]]]+=sz[sa[i]];
}
struct D{int l,r;}e[N];
struct data{int l,r,id;}q[N];
inline bool comp(data i,data j){return i.l/B!=j.l/B?i.l/B<j.l/B:i.r<j.r;}
namespace solo{
char w[N][M];int v[M][M];ll ans[N];
inline void add(int x){v[e[x].l][e[x].r]++;}
inline void del(int x){v[e[x].l][e[x].r]--;}
inline ll solve(int x){
int len=strlen(w[x]+1),p,c;ll ret=0;
for(int i=1;i<=len;i++){
p=1;
for(int j=i;j<=len;j++){
c=w[x][j]-'a';
if(!ch[p][c])break;
p=ch[p][c];
ret+=v[i][j]*sz[p];
}
}
return ret;
}
void main(){
for(int i=1;i<=Q;i++){
scanf("%s",w[i]+1);
gi(q[i].l);gi(q[i].r);q[i].id=i;q[i].l++;q[i].r++;
}
sort(q+1,q+Q+1,comp);
int l=1,r=0;
for(int i=1;i<=Q;i++){
while(r<q[i].r)add(++r);
while(l>q[i].l)add(--l);
while(r>q[i].r)del(r--);
while(l<q[i].l)del(l++);
ans[q[i].id]=solve(q[i].id);
}
for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
}
}
namespace sol{
char w[N];int pos[N],f[N][20];
inline int qry(int x,int y){
if(len[x]<y)return 0;
for(int i=19;i>=0;i--)
if(f[x][i] && len[f[x][i]]>=y)x=f[x][i];
return sz[x];
}
void main(){
int x,y,le,p,now;
for(int i=1;i<=cnt;i++)f[i][0]=fa[i];
for(int j=1;j<20;j++)
for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=Q;i++){
scanf("%s",w+1);le=strlen(w+1);
p=1;now=0;
for(int j=1;j<=le;j++){
int c=w[j]-'a';
if(ch[p][c])p=ch[p][c],now++;
else{
while(p>1 && !ch[p][c])p=fa[p];
if(ch[p][c])now=len[p]+1,p=ch[p][c];
else now=0;
}
pos[j]=p;g[j]=now;
}
gi(x);gi(y);x++;y++;
ll ret=0;
for(int j=x;j<=y;j++)
if(g[e[j].r]>=e[j].r-e[j].l+1)
ret+=qry(pos[e[j].r],e[j].r-e[j].l+1);
printf("%lld\n",ret);
}
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m>>Q>>K;
scanf("%s",s+1);
for(int i=1;i<=n;i++)ins(s[i]-'a');
priwork();
for(int i=1;i<=m;i++)gi(e[i].l),gi(e[i].r),e[i].l++,e[i].r++;
if(K<M)solo::main();
else sol::main();
return 0;
}

LOJ #6031 字符串的更多相关文章

  1. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  2. loj 6031「雅礼集训 2017 Day1」字符串

    loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...

  3. loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)

    题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...

  4. 【SAM】loj#6401. 字符串

    网上有篇题解写的是线段树合并维护求值? 题目描述 有一个只包含小写字母,长度为 $n$ 的字符串 $S$ .有一些字母是好的,剩下的是坏的. 定义一个子串 $S_{l\ldots r}$是好的,当且仅 ...

  5. 雅礼集训 2017 Day1

    T1:loj 6029 市场 题目大意: 维护一个数据结构支持区间加 区间除法 区间求最小值 区间求和 思路: 用线段树维护区间加 区间求最小值 区间和 对于区间除法 注意到除数d很大而加法的w很小 ...

  6. Contest Record

    Contest 1135 at HZOI Problem A: 优美的棋发现一个可以证明的规律就是了……忘记给<<运算的左边变量转化为long long类型了,结果挂了20分……以后一定记 ...

  7. 【LOJ#3095】[SNOI2019]字符串(后缀数组)

    [LOJ#3095][SNOI2019]字符串(后缀数组) 题面 LOJ 题解 首先画图看看如何比较两个串的大小,发现这个东西等价于求两个相邻的后缀的\(LCP\). 一个做法是求出\(SA\),然后 ...

  8. LOJ 3049: 洛谷 P5284: 「十二省联考 2019」字符串问题

    题目传送门:LOJ #3049. 题意简述: 给定一个长度为 \(n\) 的母串 \(S\). 有 \(n_a\) 个 A 类串,都是 \(S\) 的子串,以区间的形式给出. 有 \(n_b\) 个 ...

  9. LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)

    题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...

随机推荐

  1. Alpha第三天

    Alpha第三天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  2. C语言博客作业—一二维数组

    一.PTA实验作业 题目1:7-2 求整数序列中出现次数最多的数 1. 本题PTA提交列表 2. 设计思路 Begin 输入整数个数N 定义数组a[N] 输入数组a for(i 0 to N-1){/ ...

  3. 20162323周楠《Java程序设计与数据结构》第六周总结

    学号 2016-2017-2 <程序设计与数据结构>第六周学习总结 教材学习内容总结 继承:从已有类派生一个新类,是面向对象程序设计的一个特点 在Java中只支持单继承,不支持多继承 继承 ...

  4. 学号:201621123032 《Java程序设计》第3周学习总结

    1:本周学习总结 1. 写出你认为本周学习中比较重要的知识点关键词. 类,对象,封装,继承,方法. 2. 用思维导图或者Onenote或其他工具将这些关键词组织起来 2:书面作业 2.1:以面向对象方 ...

  5. find命令之(-atime,-ctime,-mtime)

    关于find命令,以拙见总结如下: >>>定义: find命令用来在指定目录下查找文件. 任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则fin ...

  6. animation & @keyframes 实现loading效果

    效果图截图如下: 直接上代码: html <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...

  7. nyoj 苹果

    苹果 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 ctest有n个苹果,要将它放入容量为v的背包.给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值. ...

  8. var、let、const区别

    1.let不存在变量提升,必须升明后才可用. 'use strict'; (function(){ console.log(varTest); console.log(letTest); var va ...

  9. WIN10系统触摸板快捷键

    快捷的手势操作,有时候会让人脱离鼠标,只要不是非用不可的情况,基本上这些常用手势就能让我们摆脱鼠标携带不便或者桌子地方小的烦恼.iOS上的快捷手势很是受欢迎,win10上却鲜有人知晓,尤其是非开发人员 ...

  10. H5 FormData对象的作用及用法

    JS: function uploadFileAndParam() { var url = "http://localhost:42561/api/upload/UploadPost&quo ...