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\)串的个数 那就直接做一下乘法就好 这个怎么求? 枚举一个位置 ...
随机推荐
- Linux产生随机数的几种方法
.echo $RANDOM .openssl rand -base64 .date +%n%N .head /dev/urandom |cksum .cat /proc/sys/kernel/rand ...
- MySQL批量插入大量数据方法
在MySQL数据库中,如果要插入上百万级的记录,用普通的insert into来操作非常不现实,速度慢人力成本高,推荐使用Load Data或存储过程来导入数据,我总结了一些方法分享如下,主要基于My ...
- PHP 根据IP获取地理位置
/** * 根据用户IP获取用户地理位置 * $ip 用户ip */ function get_position($ip){ if(empty($ip)){ return '缺少用户ip'; } $u ...
- python 爬虫豆瓣top250
网页api:https://movie.douban.com/top250?start=0&filter= 用到的模块:urllib,re,csv 捣鼓一上午终于好了,有些小问题 (top21 ...
- 免费证书Let’s Encrypt
我们自己也可以签发 SSL 安全证书,但是我们自己签发的安全证书不会被主流的浏览器信任,所以我们需要被信任的证书授权中心( CA )签发的安全证书.而一般的 SSL 安全证书签发服务都比较贵,比如 G ...
- [Hdu3507]Print Article(斜率优化)
Description 题意:给N个数,按顺序全部取走,每次取一段连续的区间,代价为\((S[i]-S[j])^2+M\) 其中M为一个给定的常数,\(S[i]\)为前缀和 \(N\leq 50000 ...
- UVA_10653 公主与王子 #刘汝佳DP题刷完计划
题意如蓝书66页例题27所示. 这个问题描述了一个LCS的特殊情况——单个字符串内所有元素各不相同. 题目要求输入两个数字串,A,B,要求求出最长公共字串.且数字上限是256*256. 做法:数组A表 ...
- 记一次Entity Framework 项目的优化过程
在博客园看了不少其他大神的经验.今天也抽空贡献点自己的经验(并不是说自己也是大神..小弟还只新手程序员去年才毕业的) 好了废话不多说,直接进入主题.(具体的好坏各位看官就随便看看吧..没有什么好坏之分 ...
- 【Gas Station】cpp
题目: There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. ...
- Python+Selenium练习篇之10-刷新当前页面
本文介绍如何调用webdriver中刷新页面的方法. 相关脚本代码如下: # coding=utf-8import timefrom selenium import webdriver driver ...