LOJ#2083. 「NOI2016」优秀的拆分
$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」优秀的拆分的更多相关文章
- 「NOI2016」优秀的拆分 解题报告
「NOI2016」优秀的拆分 这不是个SAM题,只是个LCP题目 95分的Hash很简单,枚举每个点为开头和末尾的AA串个数,然后乘一下之类的. 考虑怎么快速求"每个点为开头和末尾的AA串个 ...
- loj#2128. 「HAOI2015」数字串拆分 矩阵乘法
目录 题目链接 题解 代码 题目链接 loj#2128. 「HAOI2015」数字串拆分 题解 \(f(s)\)对于\(f(i) = \sum_{j = i - m}^{i - 1}f(j)\) 这个 ...
- LOJ#2086. 「NOI2016」区间
$n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...
- *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 ...
- LOJ#2084. 「NOI2016」网格
$n,m \leq 1e9$,$n*m$的网格中有$c \leq 1e5$个是黑的,其他是白的.问:使至少两个白的不连通,最少需要再把几个白的涂黑. 可以发现答案是-1,0,1,2啦.-1要么没白的, ...
- Loj #2554. 「CTSC2018」青蕈领主
Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...
- Loj #2570. 「ZJOI2017」线段树
Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...
- UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]
#219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...
- 【BZOJ4650】【NOI2016】优秀的拆分(后缀数组)
[BZOJ4650][NOI2016]优秀的拆分(后缀数组) 题面 BZOJ Uoj 题解 如果我们知道以某个位置为开始/结尾的\(AA\)串的个数 那就直接做一下乘法就好 这个怎么求? 枚举一个位置 ...
随机推荐
- SummerVocation_Learning--java的String 类
java中String属于java.lang的package包,是一个类.代表不可变的字符序列. String类的常见构造方法: String(String original),创建一个对象为orig ...
- 微信小游戏 demo 飞机大战 代码分析 (三)(spirit.js, animation.js)
微信小游戏 demo 飞机大战 代码分析(三)(spirit.js, animation.js) 微信小游戏 demo 飞机大战 代码分析(一)(main.js) 微信小游戏 demo 飞机大战 代码 ...
- 十一、Shell 文件包含
Shell 文件包含 和其他语言一样,Shell 也可以包含外部脚本.这样可以很方便的封装一些公用的代码作为一个独立的文件. Shell 文件包含的语法格式如下: . filename # 注意点号( ...
- Shell脚本使用汇总整理——文件夹及子文件备份脚本
Shell脚本使用汇总整理——文件夹及子文件备份脚本 Shell脚本使用的基本知识点汇总详情见连接: https://www.cnblogs.com/lsy-blogs/p/9223477.html ...
- 自动化运维工具——ansible模板与roles(四)
一. 模板Templates 文本文件,嵌套有脚本(使用模板编程语言编写) Jinja2语言,使用字面量,有下面形式 字符串:使用单引号或双引号 数字:整数,浮点数 列表:[item1, item2, ...
- Python_深浅拷贝
深浅拷贝 ‘copy’和'='的区别:copy会开辟一个新的空间,而‘=’不会. 浅copy只会copy第一层,再里边的就进行共享了. 需要记住的是copy之后记住的是内存寻址地址,而浅copy时如果 ...
- eclipse projectExplorer视图(以包的方式显示)与navigator视图切换(以文件夹的方式显示)及树状视图与平面视图的切换
projectExplorer与navigator的切换 projectExplorer视图效果 想要此视图效果步骤如下: 分割------------------------------------ ...
- PHP代码中出现中文乱码怎么办?
header("Content-type:text/html;charset=utf-8"); //加上这个就OK //示例 : class WechatController ex ...
- php中处理字符串的常见函数
编写程序的时候,经常要处理字符串,最基本就是字符串的查找,在php检测字符串中是否包含指定字符串可以使用正则,如果你对正则不了解,那么有几个函数可以为您提供方便. 1. strstr strstr() ...
- I miss you, Jenny【我想念你,jenny】
I miss you, Jenny Forrest Gump: 阿甘正传 You died on a Saturday morning. And I had you placed here our t ...