luogu1117 优秀的拆分 (后缀数组)
考虑分别计算每个位置作为AA的末尾或者BB的开头的个数 最后乘一乘就是答案
据说是套路的计算AA的方法:
首先枚举A的长度L,然后每L个字符当做一个关键点,这样的话,一个AA包含且只包含相邻两个关键点(记为a,b),而且满足lcp(a,b)+lcs(a,b)-1>=L 手画一下就能看出来
于是SA搞lcp 倒过来再SA搞lcs 最后差分一下统计答案即可
#include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
#define MP make_pair
using namespace std;
typedef long long ll;
const int maxn=3e4+; inline char gc(){
return getchar();
static const int maxs=<<;static char buf[maxs],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,maxs,stdin),p1==p2)?EOF:*p1++;
}
inline ll rd(){
ll x=;char c=gc();bool neg=;
while(c<''||c>''){if(c=='-') neg=;c=gc();}
while(c>=''&&c<='') x=(x<<)+(x<<)+c-'',c=gc();
return neg?(~x+):x;
} char str[maxn];
int lg2[maxn],N; struct SA{
int cnt[maxn*],tmp[maxn*],rnk[maxn*],sa[maxn*],hei[maxn];
int st[maxn][],n; inline void build(char *s){
int i,j=,k,m=;
CLR(cnt,);CLR(rnk,);
for(i=;i<=n;i++) cnt[s[i]-'a']=;
for(i=;i<=m;i++) cnt[i]+=cnt[i-];
for(i=;i<=n;i++) rnk[i]=cnt[s[i]-'a'];
for(k=;j!=n;k<<=){
CLR(cnt,);
for(i=;i<=n;i++) cnt[rnk[i+k]]++;
for(i=;i<=m;i++) cnt[i]+=cnt[i-];
for(i=n;i;i--) tmp[cnt[rnk[i+k]]--]=i;
CLR(cnt,);
for(i=;i<=n;i++) cnt[rnk[i]]++;
for(i=;i<=m;i++) cnt[i]+=cnt[i-];
for(i=n;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i];
memcpy(tmp,rnk,sizeof(rnk));
rnk[sa[]]=j=;
for(i=;i<=n;i++){
if(tmp[sa[i]]!=tmp[sa[i-]]||tmp[sa[i]+k]!=tmp[sa[i-]+k]) j++;
rnk[sa[i]]=j;
}m=j;
} hei[]=;
for(i=,j=;i<=n;i++){
if(rnk[i]==) continue;
if(j) j--;
int x=sa[rnk[i]-];
while(i+j<=n&&x+j<=n&&s[i+j]==s[x+j]) j++;
hei[rnk[i]]=j;
}
// for(i=1;i<=n;i++) printf("hei:%d %d ; rnk:%d ; sa:%d \n",i,hei[i],rnk[i],sa[i]);
for(i=n;i;i--){
st[i][]=hei[i];
for(j=;i+(<<j)-<=n;j++){
st[i][j]=min(st[i][j-],st[i+(<<(j-))][j-]);
}
}
} inline int query(int x,int y){ //x,y:pos
if(x==y) return n-y+;
int l=min(rnk[x],rnk[y])+,r=max(rnk[x],rnk[y]);
// printf("~%d %d\n",l,r);
int k=lg2[r-l+];
return min(st[l][k],st[r-(<<k)+][k]);
}
}fw,bw; int end[maxn],beg[maxn]; int main(){
//freopen("","r",stdin);
int i,j,k;
for(i=;i<=;i++) lg2[i]=lg2[i>>]+;
for(int T=rd();T;T--){
scanf("%s",str+);N=strlen(str+);
fw.n=bw.n=N;
fw.build(str);
reverse(str+,str+N+);
bw.build(str);
CLR(end,);CLR(beg,);
for(int l=;l<=N;l++){
i=l+;
for(;i<=N;i+=l){
int lcp=min(l,fw.query(i-l,i)),lcs=min(l,bw.query(N-i+,N-(i-l)+));
// printf("!%d %d %d %d\n",i,i-l,lcp,lcs);
if(lcp+lcs->=l){
end[i+l-lcs]++,end[i+lcp]--;
// printf("add A:%d %d\n",i+l-lcs,i+lcp-1);
beg[i-l-lcs+]++,beg[i-*l+lcp+]--;
// printf("add B:%d %d\n",i-l-lcs+1,i-2*l+lcp);
}
}
}
for(i=;i<=N;i++) end[i]+=end[i-],beg[i]+=beg[i-];
ll ans=;
for(i=;i<N;i++){
ans+=end[i]*beg[i+];
}
printf("%lld\n",ans);
}
return ;
}
luogu1117 优秀的拆分 (后缀数组)的更多相关文章
- NOI 2016 优秀的拆分 (后缀数组+差分)
题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...
- [NOI2016]优秀的拆分 后缀数组
题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...
- UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]
#219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...
- BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)
BZOJ 洛谷 令\(st[i]\)表示以\(i\)为开头有多少个\(AA\)这样的子串,\(ed[i]\)表示以\(i\)结尾有多少个\(AA\)这样的子串.那么\(Ans=\sum_{i=1}^{ ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...
- BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
我们只需要统计在某一个点开始的形如$AA$字符串个数,和结束的个数相乘求和. 首先枚举循环节的长度L.即$\mid (A) \mid=L$ 然后肯定会经过s[i]和[i+L]至少两个点. 然后我们可以 ...
- [NOI2016]优秀的拆分(SA数组)
[NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...
- 【BZOJ4650】【NOI2016】优秀的拆分(后缀数组)
[BZOJ4650][NOI2016]优秀的拆分(后缀数组) 题面 BZOJ Uoj 题解 如果我们知道以某个位置为开始/结尾的\(AA\)串的个数 那就直接做一下乘法就好 这个怎么求? 枚举一个位置 ...
- 【BZOJ4650】[NOI2016] 优秀的拆分(后缀数组)
点此看题面 大致题意: 定义将一个字符串拆成\(AABB\)的形式为优秀拆分,求一个字符串所有子串的优秀拆分个数. 后缀数组 这题可是一道后缀数组黑题啊. 其实看完题解这题还是挺简单的. 大致思路 显 ...
随机推荐
- AOP中使用Aspectj对接口访问权限进行访问控制
切面编程的应用案例比较多,在统一的日志处理,鉴权过程中都会用的AOP原理,本文主要针对对进口的访问权限进行控制为例,说明 切面编程的使用: 1.使用Aspectj的方式进行切面编程: 2.编码环境,s ...
- GNUstep 快捷键编译
$ gcc `gnustep-config --objc-flags` -L /GNUorld.m -o helloworld -lgnustep-base -lobjc $ ./helloworld ...
- JavaScript中的高阶函数
之前写的<JavaScript学习手册>,客户跟我说有些内容不适合初学者,让我删了,感觉挺可惜的,拿到这里和大家分享. JavaScript中的一切都是对象,这句话同样适用于函数.函数对象 ...
- 前后端分离djangorestframework—— 在线视频平台接入第三方加密防盗录视频
加密视频 在以后的开发项目中,很可能有做在线视频的,而在线视频就有个问题,因为在线播放,就很有可能视频数据被抓包,如果这个在线视频平台有付费视频的话,这样就会有人做点倒卖视频的生意了,针对这个问题,目 ...
- python3 判断数据类型
def estType(): eventList = [1, 'Tom', {'name': 'Lucy', 'age': 16, 'grade': 98}] print(type(eventList ...
- 使用laravel-admin后台sdk报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID、Provisional headers are shown
报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID请先确定自己的资源url是否可以确实访问到(地址正确与否.访问权限是否开启等) 若n ...
- 歌曲的BPM (Beat Per Minute)--每分钟节拍数
因为老爸喜欢跳舞,总让我帮他整理舞曲,一会儿要慢三,一会儿要慢四,一会儿又要快四....我真的分不清啊 我想啊,慢三,慢四这些应该是歌曲的节拍吧(后来得知专业术语叫BPM),于是就在网上搜看看能不能通 ...
- topjui中combobox使用
1.创建combobox的方法 常用的一种是通过Js定义,一种是通过在input输入框中定义,还有一种通过在selete标签中定义,可以去看easyui的官方文档 http://www.jeasyui ...
- enex 转 md 格式的几种方式(免费版/氪金版)
因为最近有读者投稿,用的是印象笔记,文件格式为 .enex ,一般发文章都用 markdown 格式,这叫我好生苦恼,于是乎,Google 搜了一下,找到了如下解决办法. 氪金版: 我只找到了一款比较 ...
- Java 开发笔记2
Java获取参数名称 https://blog.csdn.net/z69183787/article/details/81117525 DefaultParameterNameDiscoverer() ...