点此看题面

大致题意: 定义将一个字符串拆成\(AABB\)的形式为优秀拆分,求一个字符串所有子串的优秀拆分个数。

后缀数组

这题可是一道后缀数组黑题啊。

其实看完题解这题还是挺简单的。

大致思路

显然可以考虑对于每个位置\(i\)分别处理\(AA\)和\(BB\)的个数\(pre_i\)和\(nxt_i\),最后扫一遍相乘求和即可。

而这显然是可以用后缀数组来求的。

首先,我们枚举\(i\)来表示当前所找的\(AA\)型的字符串中\(A\)的长度。

然后枚举\(j\)和\(k\),其中\(j=t\cdot i,k=(t+1)\cdot i(t\)为正整数\()\)。

接下来,我们求出\(LCP(j,k)\)和\(LCS(j-1,k-1)\),分别记作\(x\)和\(y\)(注意\(LCS\)可以通过对一个反转后的字符串求\(LCP\)得到)。

如果\(x+y<i\),就说明当位置无法得到一个长大于等于\(i\)的\(AABB\)型字符串,可以直接跳过。

否则,就可以更新\(pre\)数组和\(nxt\)数组了。

但暴力更新依然会\(TLE\)。

考虑到每次更新的恰好是一段连续区间,则我们可以考虑差分

最后扫一遍对\(pre\)数组和\(nxt\)数组求和然后相乘求解答案即可。

代码

#include<bits/stdc++.h>
#define N 30000
#define LL long long
#define min(x,y) ((x)<(y)?(x):(y))
#define swap(x,y) (x^=y^=x^=y)
using namespace std;
int n,pre[N+5],nxt[N+5];char s1[N+5],s2[N+5];
class Class_SuffixArray//后缀数组
{
private:
int n,SA[N+5],Height[N+5],rk[N+5],pos[N+5],tot[N+5];
inline void RadixSort(int S)
{
register int i;
for(i=0;i<=S;++i) tot[i]=0;
for(i=1;i<=n;++i) ++tot[rk[i]];
for(i=1;i<=S;++i) tot[i]+=tot[i-1];
for(i=n;i;--i) SA[tot[rk[pos[i]]]--]=pos[i];
}
inline void GetSA(char *s)
{
register int i,k,Size=122,cnt=0;
for(i=1;i<=n;++i) rk[pos[i]=i]=s[i-1];
for(RadixSort(Size),k=1;cnt<n;k<<=1)
{
for(Size=cnt,cnt=0,i=1;i<=k;++i) pos[++cnt]=n-k+i;
for(i=1;i<=n;++i) SA[i]>k&&(pos[++cnt]=SA[i]-k);
for(RadixSort(Size),i=1;i<=n;++i) pos[i]=rk[i];
for(rk[SA[1]]=cnt=1,i=2;i<=n;++i) rk[SA[i]]=(pos[SA[i-1]]^pos[SA[i]]||pos[SA[i-1]+k]^pos[SA[i]+k])?++cnt:cnt;
}
}
inline void GetHeight(char *s)
{
register int i,j,k=0;
for(i=1;i<=n;++i) rk[SA[i]]=i;
for(i=1;i<=n;++i)
{
if(k&&--k,!(rk[i]^1)) continue;
j=SA[rk[i]-1];
while(i+k<=n&&j+k<=n&&!(s[i+k-1]^s[j+k-1])) ++k;
Height[rk[i]]=k;
}
}
class Class_RMQ
{
private:
#define LogN 15
int Log2[N+5],Min[N+5][LogN+5];
public:
inline void Init(int len,int *data)
{
register int i,j;
for(i=2;i<=len;++i) Log2[i]=Log2[i>>1]+1;
for(i=1;i<=len;++i) Min[i][0]=data[i];
for(j=1;(1<<j-1)<=len;++j) for(i=1;i+(1<<j-1)<=len;++i) Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
}
inline int GetMin(int l,int r) {register int k=Log2[r-l+1];return min(Min[l][k],Min[r-(1<<k)+1][k]);}
}RMQ;
public:
inline void Init(int len,char *s) {n=len,GetSA(s),GetHeight(s),RMQ.Init(n,Height);}
inline int LCP(int x,int y) {return x^y?(rk[x]>rk[y]&&swap(x,y),RMQ.GetMin(rk[x]+1,rk[y])):n-x+1;}
}S1,S2;//分别存储原串和翻转后的串,分别用于求解LCP和LCS
int main()
{
register int test_tot,i,j,k,x,y,z,lst;LL ans;scanf("%d",&test_tot);
while(test_tot--)
{
for(memset(&S1,0,sizeof(S1)),memset(&S2,0,sizeof(S2)),i=0;i<=n;++i) s1[i]=s2[i]='\0',pre[i]=nxt[i]=0;//清空
for(scanf("%s",s1),n=strlen(s1),i=0;i<n;++i) s2[i]=s1[n-i-1];//读入
for(S1.Init(n,s1),S2.Init(n,s2),i=1;i<=(n>>1);++i) for(j=i,k=i<<1,lst=0;k<=n;j+=i,k+=i) j>lst&&((x=S1.LCP(j,k))+(y=S2.LCP(n-j+1,n-k+1))>i&&(++pre[k+x-1],--pre[k-y+i-1],++nxt[j-y+1],--nxt[j+x-i+1]),lst=j+x-1);//差分
for(i=n;i;--i) pre[i]+=pre[i+1];for(i=1;i<=n;++i) nxt[i]+=nxt[i-1];for(ans=0,i=1;i<n;++i) ans+=1LL*pre[i]*nxt[i+1];//统计答案
printf("%lld\n",ans);
}
return 0;
}

【BZOJ4650】[NOI2016] 优秀的拆分(后缀数组)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. [NOI2016]优秀的拆分(SA数组)

    [NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...

  7. BZOJ4650 [NOI2016]优秀的拆分 【后缀数组】

    题目 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆 分是优秀的.例如,对于字符串 aabaabaa,如果令 A=aabA=aa ...

  8. bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...

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

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

  10. UOJ#219/BZOJ4650 [NOI2016]优秀的拆分 字符串 SA ST表

    原文链接http://www.cnblogs.com/zhouzhendong/p/9025092.html 题目传送门 - UOJ#219 (推荐,题面清晰) 题目传送门 - BZOJ4650 题意 ...

随机推荐

  1. 洛谷P1932 A+B A-B A*B A/B A%B Problem

    P1932 A+B A-B A*B A/B A%B Problem 题目背景 这个题目很新颖吧!!! 题目描述 求A.B的和差积商余! 由于数据有修改,减法运算结果可能带负号! 输入输出格式 输入格式 ...

  2. jmeter-提取器之JSON Path PostProcessor

    后置处理器添加 json path postprocessor. 用处: 当前接口响应返回的json中提取内容,作为变量可以在不同的请求中传递. 1. json path postprocessor ...

  3. generator-yield到底是个啥

    咱们通过上篇文章的简单介绍,已经了解到yield是放弃执行,放弃现在继续执行的权利,把权利让给别人,什么时候想继续执行的时候,再调一次就好.接下来咱们说两件事,就是yield是一个很有意思的东西,它可 ...

  4. 记录在APIO2019前

    2019-05-07 嗯, 只报名参加了APIO. 今天是五月七号,距离前往帝都参加我的退役之战, 还有八天(5.15) 然后没什么可说的, 就是记录一下这几天吧. 今天下午去学了虚树(其实没什么的) ...

  5. git教程3-分支

    https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E7%AE%A1%E7%90%86 ...

  6. spark_20180328

    // 2.1 条件表达式val x = 2val s = if (x > 0) 1 else -1if (x > 0) "positive" else -1// 返回值 ...

  7. redis结合springboot 无法注入redisTemplate问题

    报错: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean o ...

  8. vue——做了一个幼稚的小页面

    我的小花花没有转起来,不开心  ̄へ ̄

  9. 关于String的split方法

    在做剑指offer的时候,有一道替换空格的题,立刻就想到用这个split方法来做,但发现,这个方法会丢掉字符串最后的空格??? 百度后,知道原因,这里直接复制粘贴了: 在使用java中的split按照 ...

  10. 【Linux】让Ubuntu 支持 GBK等字符集,解决中文乱码

    对GBK,GB2312,GB18030字符集的支持是UBUNTU中文乱码的罪魁祸首,其实我们可以在保持UTF-8为默认编码的条件下添加对这几个编码的支持,以解决中文乱码问题. 我想这个问题肯定有其他人 ...