题意:统计一段字符串中形如UVU的子串个数(其中V的长度固定为g)。

问题等价于求满足$g+1\leqslant |j-i|\leqslant g+LCP(i,j)$的后缀(i,j)的对数,即$\sum\limits_{i<j}[g+1\leqslant |j-i|\leqslant g+LCP(i,j)]$。

由于将原串反转后的后缀(i,j)的LCP等于其在原串的后缀自动机上对应结点的LCA的最大长度,可以枚举LCA,在fail树上将right数组启发式合并即可。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+,M=;
char s[N];
int n,fa[N],go[N][M],mxl[N],last,tot,g,ss[N],c[N],ka;
int rt[N],ls[N*],rs[N*],sum[N*],tot2,ans[N];
#define mid ((l+r)>>1)
int newnode2() {int u=++tot2; sum[u]=ls[u]=rs[u]=; return u;}
void upd(int& u,int p,int l=,int r=n-) {
if(!u)u=newnode2();
sum[u]++;
if(l==r)return;
p<=mid?upd(ls[u],p,l,mid):upd(rs[u],p,mid+,r);
}
void mg(int& u,int v) {
if(!u||!v) {u=u|v; return;}
sum[u]+=sum[v];
mg(ls[u],ls[v]),mg(rs[u],rs[v]);
}
int qry(int u,int L,int R,int l=,int r=n-) {
if(l>=L&&r<=R)return sum[u];
if(l>R||r<L)return ;
return qry(ls[u],L,R,l,mid)+qry(rs[u],L,R,mid+,r);
}
void dfs(int u,int v,int l=,int r=n-) {
if(!sum[v])return;
if(l==r) {
ans[u]+=qry(rt[u],l+(+g),l+(mxl[u]+g));
ans[u]+=qry(rt[u],l-(mxl[u]+g),l-(+g));
return;
}
dfs(u,ls[v],l,mid),dfs(u,rs[v],mid+,r);
}
int newnode(int l) {int u=++tot; rt[u]=ans[u]=,mxl[u]=l,memset(go[u],,sizeof go[u]); return u;}
void add(int ch,int r) {
int p=last,np=last=newnode(mxl[p]+);
upd(rt[np],r);
for(; p&&!go[p][ch]; p=fa[p])go[p][ch]=np;
if(!p)fa[np]=;
else {
int q=go[p][ch];
if(mxl[q]==mxl[p]+)fa[np]=q;
else {
int nq=newnode(mxl[p]+);
memcpy(go[nq],go[q],sizeof go[q]);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(; p&&go[p][ch]==q; p=fa[p])go[p][ch]=nq;
}
}
}
void solve() {
for(int i=; i<=tot; ++i)c[i]=;
for(int i=; i<=tot; ++i)++c[mxl[i]];
for(int i=; i<=tot; ++i)c[i]+=c[i-];
for(int i=; i<=tot; ++i)ss[--c[mxl[i]]]=i;
for(int i=tot-; i>=; --i) {
int v=ss[i],u=fa[v];
if(!u)continue;
if(sum[rt[v]]>sum[rt[u]])swap(rt[u],rt[v]);
dfs(u,rt[v]),mg(rt[u],rt[v]);
ans[u]+=ans[v];
}
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
scanf("%d%s",&g,s),n=strlen(s);
tot=tot2=,last=newnode();
for(int i=; i<n; ++i)add(s[i]-'a',i);
solve();
printf("Case %d: %d\n",++ka,ans[]);
}
return ;
}

UVA - 10829 L-Gap Substrings (后缀自动机+线段树启发式合并)的更多相关文章

  1. Bzoj2534:后缀自动机 主席树启发式合并

    国际惯例的题面:考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?显然j>i+L,因为我们选择的串不能是空串.另外考虑i和j的最长公共前缀(也就是说其p ...

  2. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  3. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  4. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  5. BZOJ1396: 识别子串(后缀自动机 线段树)

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  6. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  7. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  8. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  9. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

随机推荐

  1. Beego开启热升级

    1.打开配置 beego.BConfig.Listen.Graceful = true 2.写入pid 程序入口main()函数里写入pid func writePid() { fileName := ...

  2. 4-2 编辑器之神--vim

    vim vi:Visual editor文本编辑器 文本:ascii,Unicode vim:VIsual editor iMproved 官网:www.vim.org 帮助网站:Vimhelp.or ...

  3. 重学Python - Day 06 - python基础 -> linux命令行学习 -- 简单基础命令学习

    学习资源 虚拟机工具:VMWare 12 linux :Ubuntu 14 或者CentOS 6 PS:ubuntu用远程连接工具的设置方法 step 1: 输入sudo apt-get instal ...

  4. LeetCode.1128-等价多米诺骨牌对的数量(Number of Equivalent Domino Pairs)

    这是小川的第394次更新,第428篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第259题(顺位题号是1128).给定多米诺骨牌列表,当且仅当(a == c且b == d ...

  5. SQLite扫描

    SQLite的扫盲 SQLite的是一种嵌入式数据库,它的数据库就是一个文件.由于SQLite的本身是Ç写的,而且体积很小,所以经常被集成到各种应用程序中,主要在手机的应用中使用. 之前没有遇到过关于 ...

  6. 【DSP开发】【并行计算-CUDA开发】TI OpenCL v01.01.xx

    TI OpenCL v01.01.xx TI OpenCL™ Runtime Documentation Contents: Introduction OpenCL 1.1 Reference Mat ...

  7. Identification of Encryption Algorithm Using Decision Tree

    本文主要做了两件事,一是提出了一种使用C4.5算法生成的决策树来识别密文所使用的加密算法的方法,二是为这一算法设计了一个特征提取系统提取八个特征作为算法的输入,最终实现了70%~75的准确率. 准备工 ...

  8. MSSQL 索引

    INCLUDE索引作用:减少 key lookup所带来的性能开销. 效率主要体现在覆盖查询(建的索引为覆盖索引),在查询时把SELECT显示列放在INCLUDE里作为非索引健列,不用于查询只显示在结 ...

  9. 【案例分享】使用ActiveReports报表工具,在.NET MVC模式下动态创建报表

    提起报表,大家会觉得即熟悉又陌生,好像常常在工作中使用,又似乎无法准确描述报表.今天我们来一起了解一下什么是报表,报表的结构.构成元素,以及为什么需要报表. 什么是报表 简单的说:报表就是通过表格.图 ...

  10. idea-代码格式化快捷键设置(2019.1版)

    idea默认格式化快捷键是:Ctrl+Alt+L,有时会因其它软件快捷键的冲突导致失灵. 设置方法如下: 1.File -->  Settings... 2. Keymap -> Code ...