https://www.lydsy.com/JudgeOnline/problem.php?id=4650

如果能够预处理出

suf[i] 以i结尾的形式为AA的子串个数

pre[i] 以i开头的形式为AA的子串个数

ans= ∑ suf[i]*pre[i+1]

这两个数组的求法,类似bzoj 2119、3238

枚举|A|的长度len,将序列每len个分一块,取每块内第一个元素作为关键点

每个合法的AA恰好占据两个关键点

枚举每一个关键点i,取j=i+len

计算[i,n]和[j,n]的lcp,[1,i]和[1,j]的lcs(通过原串和反串的后缀数组)

假设以i为基准,lcp向后匹配的最远点为r,lcs向前匹配的最远点为l

令cnt=r-l+1 - len + 1

那么AA的开头可以是[l,r]内任意长度为len的子串,这种子串有cnt个,即pre[l,l+cnt-1] 都会加一个贡献

假设以j为基准,lcp向后匹配的最远点为r,lcs向前匹配的最远点为l

令cnt=r-l+1 - len + 1

那么AA的结尾可以是[l,r]内任意长度为len的子串,这种子串有cnt个,即pre[r,r-cnt+1] 都会加一个贡献

利用差分累计贡献

注意:

用 后缀数组,有多组数据时,除了统计数量用的v数组要清零,rank数组也要清零

后面+k 使rank 使用超过n的rank,超过n的rank存储的时上一组数据的rank

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> #define N 30002 using namespace std; int n;
char s[N]; int pre[N],suf[N]; int Log[N]; struct SA
{
int a[N];
int sa[][N],rk[][N];
int v[N];
int p,q;
int k;
int height[N];
int st[N][]; void mul(int *sa,int *rk,int *SA,int *RK)
{
for(int i=;i<=n;++i) v[rk[sa[i]]]=i;
for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+;i<=n;++i) SA[v[rk[i]]--]=i;
for(int i=;i<=n;++i) RK[SA[i]]=RK[SA[i-]]+(rk[SA[i]]!=rk[SA[i-]] || rk[SA[i]+k]!=rk[SA[i-]+k]);
} void pre_sa()
{
p=; q=;
memset(v,,sizeof(v));
memset(rk,,sizeof(rk));
for(int i=;i<=n;++i) v[a[i]]++;
for(int i=;i<=;++i) v[i]+=v[i-];
for(int i=;i<=n;++i) sa[p][v[a[i]]--]=i;
for(int i=;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i]]!=a[sa[p][i-]]);
for(k=;k<n;k<<=,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]);
} void pre_height()
{
int j,k=;
for(int i=;i<=n;++i)
{
j=sa[p][rk[p][i]-];
while(a[i+k]==a[j+k]) k++;
height[rk[p][i]]=k;
if(k) k--;
}
} void pre_st()
{
memset(st,,sizeof(st));
for(int i=;i<=n;++i) st[i][]=height[i];
for(int j=,k=;j<=;++j,k<<=)
for(int i=;i+k*-<=n;++i)
st[i][j]=min(st[i][j-],st[i+k][j-]);
} void pre()
{
pre_sa();
pre_height();
pre_st();
} int get(int i,int j)
{
i=rk[p][i]; j=rk[p][j];
if(i>j) swap(i,j);
i++;
int l=Log[j-i+];
return min(st[i][l],st[j-(<<l)+][l]);
}
};
SA SA1,SA2; void solve()
{
memset(pre,,sizeof(pre));
memset(suf,,sizeof(suf));
int j;
int lcp,lcs;
int cnt=;
for(int len=;len<n;++len)
{
for(int i=len;i+len<=n;i+=len)
{
j=i+len;
lcp=SA1.get(i,j);
if(lcp>len) lcp=len;
lcs=SA2.get(n-i+,n-j+);
if(lcs>len) lcs=len;
if(lcp+lcs->=len)
{
suf[j+len-lcs]++;
suf[j+lcp]--;
pre[i-lcs+]++;
pre[i+lcp-len+]--;
}
}
}
for(int i=;i<=n;++i) pre[i]+=pre[i-],suf[i]+=suf[i-];
long long ans=;
for(int i=;i<=n-;++i) ans+=1LL*suf[i]*pre[i+];
cout<<ans<<'\n';
} int main()
{
//freopen("testdata.in","r",stdin);
//freopen("__.txt","w",stdout);
int T;
scanf("%d",&T);
for(int i=;i<N;++i) Log[i]=Log[i>>]+;
while(T--)
{
scanf("%s",s+);
n=strlen(s+);
for(int i=;i<=n;++i) SA1.a[i]=s[i]-'a'+;
memcpy(SA2.a,SA1.a,sizeof(SA2.a));
reverse(SA2.a+,SA2.a+n+);
SA1.a[n+]=SA2.a[n+]=;
SA1.pre();
SA2.pre();
solve();
}
}

bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)的更多相关文章

  1. bzoj千题计划314:bzoj3238: [Ahoi2013]差异(后缀数组+st表+单调栈)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3238 跟 bzoj3879 差不多 #include<cstdio> #include ...

  2. [NOI2016]优秀的拆分 后缀数组

    题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...

  3. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

  4. bzoj千题计划319:bzoj2865: 字符串识别(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=2865 同上一篇博客 就是卡卡空间,数组改成map #include<map> #inc ...

  5. bzoj千题计划318:bzoj1396: 识别子串(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=1396 后缀自动机的parent树上,如果不是叶子节点,那么至少有两个子节点 而一个状态所代表子串的 ...

  6. BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)

    BZOJ 洛谷 令\(st[i]\)表示以\(i\)为开头有多少个\(AA\)这样的子串,\(ed[i]\)表示以\(i\)结尾有多少个\(AA\)这样的子串.那么\(Ans=\sum_{i=1}^{ ...

  7. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...

  8. BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组

    我们只需要统计在某一个点开始的形如$AA$字符串个数,和结束的个数相乘求和. 首先枚举循环节的长度L.即$\mid (A) \mid=L$ 然后肯定会经过s[i]和[i+L]至少两个点. 然后我们可以 ...

  9. [UOJ#219][BZOJ4650][Noi2016]优秀的拆分

    [UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...

随机推荐

  1. Java归并排序的递归与非递归实现

    该命题已有无数解释,备份修改后的代码 平均时间复杂度: O(NLogN)  以2为底 最好情况时间复杂度: O(NLogN) 最差情况时间复杂度: O(NLogN) 所需要额外空间: 递归:O(N + ...

  2. AMH 软件目录介绍

    AMH系统shell脚本目录:/root/amh系统所有shell脚本文件目录,不可删除. 网站运行工作根目录:/home/wwwroot面板程序与新建虚拟主机网站都存放于此目录. 其中:/home/ ...

  3. Android RadioGroup中设置默认选中RadioButton 后,选中两个的问题 解决方法

    项目中遇到多个RadioGroup中单选RadioButton ,设置了默认选中第一个 . 然后就 能选中两个RadioButton . . .. 我开始这样给设置默认选中一个的: for (int ...

  4. bzoj1047/luogu2216 理想的正方形 (单调队列)

    开b组单调队列,分别维护此时某一列中的最大/最小值 然后我每次把它们的头取出来,塞到维护行的单调队列里,就是n*n的最大/最小值 #include<bits/stdc++.h> #defi ...

  5. extern C小结

    名词解释 1.extern extern翻译为外部的,用在变量或函数之前,使其可见范围拓宽,这就是为啥叫extern吧.那它是用来干嘛的呢?当用在变量或函数之前,提示编译器到其他模块寻找其定义. 举个 ...

  6. [ZJOI2016]小星星&[SHOI2016]黑暗前的幻想乡(容斥)

    这两道题思路比较像,所以把他们放到一块. [ZJOI2016]小星星 题目描述 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星. ...

  7. linux/mac下一键删除下载失败的maven jar包

    echo 正在搜索... find . -name "*lastUpdated" | xargs rm -fr echo 搜索完毕

  8. Spring Boot实战

    Spring在java EE开发中是实际意义上的标准,但我们在开发Spring的时候可能会遇到以下令人头疼的问题: 1.大量配置文件的定义.2.与第三方软件整合的技术问题. Spring每个版本的退出 ...

  9. 区间最深LCA

    求编号在区间[l, r]之间的两两lca的深度最大值. 例题. 解:口胡几种做法.前两种基于莫队,第三种是启发式合并 + 扫描线,第四种是lct + 线段树. ①: 有个结论就是这个答案一定是点集中D ...

  10. JavaScript(JS)基本语法(一)

    https://www.cnblogs.com/haiyan123/p/7577598.html 一.JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入 ...