点此看题面

大致题意: 定义将一个字符串拆成\(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. Ocelot - .Net Core开源网关

    Ocelot - .Net Core开源网关 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10857688.html 源码地 ...

  2. [Xcode 实际操作]四、常用控件-(15)MKMapView加载简单视图

    目录:[Swift]Xcode实际操作 本文将演示地图视图的使用方法. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit //首先往视图控制 ...

  3. 帝都Day7——解放篇

    昨天晚上的problems: songfen 坠大子段和,要把[l,r]其中一个数变成P,我们要把最小的数变成p. 当L,R没有取满整个区间,P可以在[L,R]外面!!!!!!!这种情况真是令人绝望. ...

  4. CSS(二)关于position

    position有五种取值 前排说一个问题,2017-10-8日更新: transform会影响定位,导致fixed降级为absolute.无论是transform:translate(),scale ...

  5. html5 替换 历史 记录

    history.replaceState({url:"/admin/index"},null,"/admin/index"); url 是 需要替换的路径

  6. mysql执行计划 const eq_ref ref range index all

    explain:查询查询性能或者需要查看使用索引状态 一.type:连接类型  最关键的一列  效率(const>eq_ref>ref>range>index>all) ...

  7. myeclipse 上安装 Maven

    myeclipse 上安装 Maven3   环境准备: JDK 1.6 Maven 3.0.4 myeclipse 8.6.1 安装 Maven 之前要求先确定你的 JDK 已经安装配置完成.Mav ...

  8. 10-----关于DOM的时间操作

    一.JavaScript的组成 JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:文档对象 ...

  9. WebP图片格式

    腾讯科技讯 科技博客Gig‍‍‍aOM近日撰文称,谷歌(微博)试图让WebP图片格式取代JPEG等现有图片格式.虽然谷歌无法很快达成所愿,但WebP仍然会对互联网产生重大影响. 文章全文如下: 受够了 ...

  10. 与postgis相关的一些常用的sql

    create table NODES (ID SERIAL not null,geometry geography(POINTZ, 4326) null); create table EDGES (I ...