$n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种。$t \leq 10$组询问。

$n^3$过80,$n^2$过95,鬼去写正解。。

$n^2$:先枚举一次算每个位置结尾的AA形式的子串,再枚举一次用类似的方法算答案。

正解:类似,记每个位置结尾的AA的子串和每个位置开头的即可。算这个数组可用如此方法:枚举A长度$L$,每A个位置标记一个关键点。然后相邻两个关键点$a,b$,找前缀$a,b$的最长公共后缀$p$和后缀$a,b$的最长公共前缀$s$,若$p+s>L$说明这里有一些A,其中作为起点的范围是$[a-p+1,a+s-L]$,作为终点的范围$[b-p+L,b+s-1]$,相当于做了个区间加,可以差分。这样做的话,复杂度就变成$\frac{n}{1}+\frac{n}{2}+...=n \ln n$了。

找最长公共前后缀,sa或二分hash或sam均可。

 //#include<iostream>
#include<cstring>
#include<cstdio>
//#include<math.h>
//#include<set>
//#include<queue>
//#include<bitset>
//#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std; #define LL long long
int qread()
{
char c; int s=,f=; while ((c=getchar())<'' || c>'') (c=='-') && (f=-);
do s=s*+c-''; while ((c=getchar())>='' && c<=''); return s*f;
} //Pay attention to '-' , LL and double of qread!!!! int T,n;
#define maxn 60011
char s[maxn]; int f[maxn],g[maxn]; struct SAM
{
struct Node{int pre,ch[],pos,Max;}a[maxn];
int size,last;
void clear()
{
size=last=; a[].pre=-; a[].pos=a[].Max=; memset(a[].ch,,sizeof(a[].ch));
le=; memset(first,,sizeof(first));
}
int pp[maxn];
void insert(int c,int p)
{
int x=++size,y=last; memset(a[x].ch,,sizeof(a[x].ch));
a[x].Max=a[last].Max+; a[x].pos=p; pp[p]=x;
last=x;
for (;~y && !a[y].ch[c];y=a[y].pre) a[y].ch[c]=x;
if (!~y) a[x].pre=;
else if (a[a[y].ch[c]].Max==a[y].Max+) a[x].pre=a[y].ch[c];
else
{
int z=a[y].ch[c],w=++size; a[w]=a[z]; a[w].pos=p; a[w].Max=a[y].Max+;
a[z].pre=a[x].pre=w;
for (;~y && a[y].ch[c]==z;y=a[y].pre) a[y].ch[c]=w;
}
}
struct Edge{int to,next;}edge[maxn<<]; int first[maxn],le;
void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
int Log[maxn<<],rmq[][maxn<<],dep[maxn],Time,id[maxn];
void predfs(int x)
{
rmq[][++Time]=x; id[x]=Time;
for (int i=first[x];i;i=edge[i].next)
{
Edge &e=edge[i]; dep[e.to]=dep[x]+;
predfs(e.to); rmq[][++Time]=x;
}
}
void pre()
{
for (int i=;i<=size;i++) in(a[i].pre,i);
Time=; predfs();
Log[]=-; for (int i=,to=size*-;i<=to;i++) Log[i]=Log[i>>]+;
for (int j=;j<=;j++)
for (int i=,to=size*-(<<j);i<=to;i++)
rmq[j][i]=dep[rmq[j-][i]]>dep[rmq[j-][i+(<<(j-))]]?rmq[j-][i+(<<(j-))]:rmq[j-][i];
}
int qq(int x,int y)
{
x=id[pp[x]]; y=id[pp[y]]; if (x>y) x^=y^=x^=y; int l=Log[y-x+];
return a[dep[rmq[l][x]]>dep[rmq[l][y-(<<l)+]]?rmq[l][y-(<<l)+]:rmq[l][x]].Max;
}
}s1,s2;
//1 shi zheng de , 2 shi fan de int main()
{
T=qread();
while (T--)
{
scanf("%s",s+); n=strlen(s+);
s1.clear(); s2.clear();
for (int i=;i<=n;i++) s1.insert(s[i]-'a',i);
for (int i=n;i;i--) s2.insert(s[i]-'a',i);
s1.pre(); s2.pre(); memset(f,,sizeof(f));
memset(g,,sizeof(g));
for (int i=;i<=n;i++)
for (int j=i;j<=n-i;j+=i)
{
int k=j+i,p=s1.qq(j,k),s=s2.qq(j,k); p=min(p,i); s=min(s,i);
if (p+s>i) f[j-p+]++,f[j+s-i+]--,g[k-p+i]++,g[k+s]--;
} for (int i=,now=;i<=n;i++) now+=f[i],f[i]=now;
for (int i=,now=;i<=n;i++) now+=g[i],g[i]=now;
LL ans=;
for (int i=;i<n;i++) ans+=g[i]*1ll*f[i+];
printf("%lld\n",ans);
}
return ;
}

LOJ#2083. 「NOI2016」优秀的拆分的更多相关文章

  1. 「NOI2016」优秀的拆分 解题报告

    「NOI2016」优秀的拆分 这不是个SAM题,只是个LCP题目 95分的Hash很简单,枚举每个点为开头和末尾的AA串个数,然后乘一下之类的. 考虑怎么快速求"每个点为开头和末尾的AA串个 ...

  2. loj#2128. 「HAOI2015」数字串拆分 矩阵乘法

    目录 题目链接 题解 代码 题目链接 loj#2128. 「HAOI2015」数字串拆分 题解 \(f(s)\)对于\(f(i) = \sum_{j = i - m}^{i - 1}f(j)\) 这个 ...

  3. LOJ#2086. 「NOI2016」区间

    $n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...

  4. *LOJ#2085. 「NOI2016」循环之美

    $n \leq 1e9,m \leq 1e9,k \leq 2000$,求$k$进制下$\frac{x}{y}$有多少种不同的纯循环数取值,$1 \leq x \leq n,1 \leq y \leq ...

  5. LOJ#2084. 「NOI2016」网格

    $n,m \leq 1e9$,$n*m$的网格中有$c \leq 1e5$个是黑的,其他是白的.问:使至少两个白的不连通,最少需要再把几个白的涂黑. 可以发现答案是-1,0,1,2啦.-1要么没白的, ...

  6. Loj #2554. 「CTSC2018」青蕈领主

    Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...

  7. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  8. UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]

    #219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...

  9. 【BZOJ4650】【NOI2016】优秀的拆分(后缀数组)

    [BZOJ4650][NOI2016]优秀的拆分(后缀数组) 题面 BZOJ Uoj 题解 如果我们知道以某个位置为开始/结尾的\(AA\)串的个数 那就直接做一下乘法就好 这个怎么求? 枚举一个位置 ...

随机推荐

  1. http 高级配置 虚拟主机,https 编译安装

    目录 http 高级配置 虚拟主机,https 编译安装 http 重定向 https HSTS HSTS preload list http 自带的工具程序 httpd的压力测试工具 实现状态页 反 ...

  2. Python Flask搭建一个视频网站实战视频教程

    点击了解更多Python课程>>> Python Flask搭建一个视频网站实战视频教程 第1章 课程介绍 第2章 预备开发环境 第3章 项目分析.建立目录及模型规划 第4章 建立前 ...

  3. 第三章JavaScript 内置对象

    1 Number 1.1 属性 MAX_VALUE JS可以表示的最大的数字 MIN_VALUE JS可以表示的最小的数字 1.2 方法 toFixed(length) 指定保留长度的小数 toExp ...

  4. git之简单入门及操作~

    看了bili的教程,https://www.bilibili.com/video/av23853294?from=search&seid=3300012850779227291 特此整理下. ...

  5. B1007 素数对猜想

    B1007 素数对猜想 让我们定义\(d_n\)为:\(d_n =p_{n+1}−p_n\),其中\(p_i\)是第i个素数.显然有\(d_1=1\),且对于n>1有\(d_n\)是偶数.&qu ...

  6. DAG上的动态规划——嵌套矩阵问题

    问题描述:有n个矩形,每个矩形可以用两个整数a,b描述,表示它的长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋 ...

  7. 记忆化搜索:POJ1579-Function Run Fun(最基础的记忆化搜索)

    Function Run Fun Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14815 Accepted: 7659 Des ...

  8. TCP/IP网络编程之基于TCP的服务端/客户端(一)

    理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于流(stream)的套接字.TCP是Transmissi ...

  9. tensorboard页面显示No dashboards are active for current data set 问题win10系统

    如果问题如上所示,可以试下如下方法: 在文件夹中找到你的logs文件, 在空白处按住“shift”键,右键鼠标(注意鼠标不要选中任何文件),点击“Powershell”打开win10powershel ...

  10. 3 - JVM随笔分类(gc.log ,VisualVM插件介绍,VisualVM远程连接方式介绍)

    gc.log 354.2 KB 对于对应用的监控上可以使用Jdk自带的VisualVM来做可视化监控,可以查看当前服务应用进程的堆大小的走向,以及类的加载数量等,除此之外,VisualVM可以支持很多 ...