题意:给定一个字符串SSS和mmm个区间[li,ri][l_i,r_i][li​,ri​],qqq次询问,每次给定长度为kkk的字符串www和区间[a,b][a,b][a,b],求对于所有i∈[a,b]i\in[a,b]i∈[a,b],www在[li,ri][l_i,r_i][li​,ri​]内的子串在SSS中出现次数之和。

∣S∣,m,∑∣w∣≤105|S|,m,\sum|w|\leq10^5∣S∣,m,∑∣w∣≤105

看上去很不可做,但是有一个很难注意到的特殊性质:所有www串长相等,所以kq≤105kq\leq10^5kq≤105。后面记kq=wkq=wkq=w

所以k,qk,qk,q中的较小值是根号级别的,考虑数据分治

首先肯定要先建出SSS的后缀自动机

当k<qk<qk<q时,字符串很短,直接开k2k^2k2个vector记录所有区间出现的位置,然后暴力枚举www的子串,在对应的vector用aaa和bbb二分一下算出有多少个区间,乘上在后缀自动机上的size。复杂度O(qk2log⁡n)=O(wwlog⁡n)O(qk^2\log n)=O(w\sqrt w\log n)O(qk2logn)=O(ww​logn)

当k>qk>qk>q时,询问很少,可以每次单独处理。每次读入www后先预处理出www的每个前缀iii 最长的 是SSS的子串 的 后缀长度LiL_iLi​。

然后暴力把[a,b][a,b][a,b]中的区间挂到rrr上,从左到右扫一遍,设当前处理[l,r][l,r][l,r],如果Lr<r−l+1L_r<r-l+1Lr​<r−l+1,说明这个子串没有出现过,直接跳过;否则在fail树上倍增找到最靠上的满足lenp≥r−l+1len_p\geq r-l+1lenp​≥r−l+1的结点ppp,这个子串就出现了sizpsiz_psizp​次。复杂度O(qmlog⁡n)=O(mwlog⁡n)O(qm\log n)=O(m\sqrt w\log n)O(qmlogn)=O(mw​logn)

某个k=qk=qk=q的点用SOLVE2会卡常,所以特判成了SOLVE1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
#define MAXN 200005
using namespace std;
int ch[MAXN][26],fa[MAXN],tot=1,las=1;
int len[MAXN],siz[MAXN];
void insert(int c)
{int p=las,cur=++tot;len[cur]=len[las]+1,las=cur;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[q]==len[p]+1) fa[cur]=q;else{int _q=++tot;len[_q]=len[p]+1;fa[_q]=fa[q],fa[q]=fa[cur]=_q;memcpy(ch[_q],ch[q],sizeof(ch[q]));for (;ch[p][c]==q;p=fa[p]) ch[p][c]=_q;}}siz[cur]=1;
}
int a[MAXN],c[MAXN],up[MAXN][20];
inline void build(int n)
{for (int i=1;i<=tot;i++) ++c[len[i]];for (int i=1;i<=n;i++) c[i]+=c[i-1];for (int i=tot;i;i--) a[c[len[i]]--]=i;for (int i=1;i<=tot;i++){up[a[i]][0]=fa[a[i]];for (int j=1;j<20;j++) up[a[i]][j]=up[up[a[i]][j-1]][j-1];}for (int i=tot;i;i--) if (fa[a[i]]) siz[fa[a[i]]]+=siz[a[i]];
}
int n,m,k,q,l[MAXN],r[MAXN];
char s[MAXN],w[MAXN];
typedef long long ll;
namespace SOLVE1
{vector<int> lis[405][405];int pos[MAXN];void main(){for (int i=1;i<=m;i++) lis[l[i]][r[i]].push_back(i);while (q--){int a,b;scanf("%s%d%d",w+1,&a,&b);++a,++b;ll ans=0;for (int i=1;i<=k;i++){int now=1;for (int j=i;j<=k;j++){now=ch[now][w[j]-'a'];if (!now) break;ans+=(ll)siz[now]*(upper_bound(lis[i][j].begin(),lis[i][j].end(),b)-upper_bound(lis[i][j].begin(),lis[i][j].end(),a-1));}}printf("%lld\n",ans);}}
}
namespace SOLVE2
{vector<int> lis[MAXN];int pos[MAXN],maxl[MAXN];void main(){while (q--){int a,b;scanf("%s%d%d",w+1,&a,&b);++a,++b;ll ans=0;int now=1,curl=0;for (int i=a;i<=b;i++) lis[r[i]].push_back(l[i]);for (int i=1;i<=k;i++) {while (now&&!ch[now][w[i]-'a']) now=fa[now],curl=len[now];now=ch[now][w[i]-'a'],++curl;if (!now) now=1,curl=0;pos[i]=now,maxl[i]=curl;}for (int p=1;p<=k;p++)for (int j=0;j<(int)lis[p].size();j++){int u=pos[p],lim=p-lis[p][j]+1;if (maxl[p]<lim) continue;for (int i=19;i>=0;i--)if (len[up[u][i]]>=lim)u=up[u][i];ans+=siz[u];}printf("%lld\n",ans);for (int i=a;i<=b;i++) lis[r[i]].clear();}}
}
int main()
{scanf("%d%d%d%d",&n,&m,&q,&k);scanf("%s",s+1);for (int i=1;i<=n;i++) insert(s[i]-'a');build(n);for (int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]),++l[i],++r[i];if (k<=q) SOLVE1::main();elseSOLVE2::main();return 0;
}

【雅礼集训2017】字符串【后缀自动机】【数据分治】相关推荐

  1. loj #6046. 「雅礼集训 2017 Day8」爷

    #6046. 「雅礼集训 2017 Day8」爷 题目描述 如果你对山口丁和 G&P 没有兴趣,可以无视题目背景,因为你估计看不懂 -- 在第 63 回战车道全国高中生大赛中,军神西住美穗带领 ...

  2. 数据结构二之线段树Ⅱ——KiKi‘s K-Number,ball,The Child and Sequence,「雅礼集训 2017 Day1」市场,Atlantis

    值域线段树+势能线段树+扫描线 KiKi's K-Number ball The Child and Sequence 「雅礼集训 2017 Day1」市场 Atlantis KiKi's K-Num ...

  3. [LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)

    [LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相 description solution 一个到所有节点距离和最小的节点 ⇔\Leftrightarrow⇔ 树的重心(满足最重的儿 ...

  4. #6029. 「雅礼集训 2017 Day1」市场(势能,区间除)

    #6029. 「雅礼集训 2017 Day1」市场 用线段树维护数列,区间上维护最大最小值,区间和还有标记,修改时,区间加直接做,而区间除时,递归到线段树上某一区间,如果这一操作等价于区间加(也就是最 ...

  5. #6034. 「雅礼集训 2017 Day2」线段游戏 李超树

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...

  6. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+LCT+树状数组)

    description 点击查看题目内容 solution Step1 无脑建SAMSAMSAM 两个前缀的最长公共后缀就是parent−treeparent-treeparent−tree上两点的l ...

  7. LOJ #6052. 「雅礼集训 2017 Day11」DIV

    完了我是数学姿势越来越弱了,感觉这种CXRdalao秒掉的题我都要做好久 一些前置推导 首先我们很容易得出\((a+bi)(c+di)=k \Leftrightarrow ac-bd=k,ad+bc= ...

  8. 雅礼集训 2017 Day1

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

  9. ZCUM-1948: #6029. 「雅礼集训 2017 Day1」市场 线段树区间更新

    题目连接:点击打开链接 从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落. 有 n nn 个商贩,从 0∼n−1 0 \sim n - ...

最新文章

  1. 【c# 学习笔记】类实例化
  2. c/c++字符串混淆工具
  3. ubuntu突然连不上-调试方式
  4. 大数据复核_【BIM技术】三维扫描结合BIM技术在结构复核中的应用
  5. php优先级,PHP运算优先级——神一般的设定
  6. [导入]创建、查询、修改带名称空间的 XML 文件的例子
  7. [bzoj3625][Codeforces Round #250]小朋友和二叉树 (生成函数)
  8. dns迭代查询配置_人人都能看懂-关于dns服务基本知识
  9. 一文读懂区块链以及一个区块链的实现
  10. 震惊,杨幂的脸竟然出现在了她的身体上
  11. 为什么家里pm25比外面高_你绝对不会相信在家用卷发棒烫发竟然比在外面烫发更伤发?...
  12. 稀缺的“稳定”--业绩导向的基金筛选困局
  13. Linux-Ubuntu安装QQ 微信 TIM 百度网盘
  14. java开发工程师面试自我介绍_java程序员面试自我介绍范文
  15. java后台json集合传前台js
  16. 渲染用计算机功耗,【IT之家评测室】满功耗 RTX 3060 笔记本 GPU 表现如何?拯救者 R9000P 实测...
  17. 点滴:日内交易规则参考
  18. SQL的between....and 用法
  19. 让博客Docker化,轻松上手Docker
  20. 露珠----让人窒息

热门文章

  1. 掌握神经网络模型的快捷方式
  2. mysql数据压缩存储_压缩文本,然后存储在mysql数据库中
  3. ajax 偶尔302,关于Ajax 中response出现302的一点见解
  4. textjoin去重_SuperJoinText这个函数,弥补了TEXTJOIN的缺憾
  5. springboot2 多线程写入数据_解决SpringBoot项目使用多线程处理任务时无法通过@Autowired注入bean问题...
  6. 数据结构——哈弗曼编码问题
  7. 数据结构—— 基于二叉树的算术表达式求值
  8. 问题 C: 【例2-3】围圈报数
  9. leedcode04:转换字符串的最少操作次数
  10. Java当中捕获异常