BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组
我们只需要统计在某一个点开始的形如$AA$字符串个数,和结束的个数相乘求和。
首先枚举循环节的长度L。即$\mid (A) \mid=L$
然后肯定会经过s[i]和[i+L]至少两个点。
然后我们可以枚举,然后求出循环节循环的次数、起点、终点,然后发现答案更新是一段$+1$的操作,
然后就可以用差分的思想更新即可。
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 70005
int _log2[maxn];
struct Suffix_Array{
int s[maxn];
int cnt[maxn],sa[maxn],rk[maxn],tmp[maxn],h[maxn];
int st[maxn][16];
void build(int n,int m)
{
n++; int i,j,k;
F(i,0,n*2+5) sa[i]=rk[i]=tmp[i]=h[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
for (k=1;k<=n;k<<=1)
{
F(i,0,n-1){j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,n*sizeof(int));memcpy(sa,tmp,n*sizeof(int));
if (j>=n-1) break;
}
for (i=k=0;i<n;h[rk[i++]]=k)
for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
F(i,0,n-1) st[i][0]=h[i];
F(i,1,15) F(j,0,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
int query(int l,int r)
{
int k=_log2[r-l+1];
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int lcp(int a,int b)
{
int aa=rk[a],bb=rk[b];
return query(min(aa,bb)+1,max(aa,bb));
}
}SA,SB; int t,n; char s[maxn];
int a[maxn],b[maxn];
int ca[maxn],cb[maxn]; void solve(int L)
{
for (int i=0;i+L<n;i+=L)
if (s[i]==s[i+L]){
int lcp=SA.lcp(i,i+L),rcp=SB.lcp(n-i,n-i-L);
if ((lcp+rcp)/L+1<2) continue;
else
{
int xl=i-rcp,xr=i-rcp+(lcp+rcp-L);// printf("%d -- %d\n",xl,xr);
int yr=i+lcp+L,yl=i+lcp+L-(lcp+rcp-L);// printf("%d -- %d\n",yl,yr);
ca[xl]++;ca[xr+1]--;cb[yl]++;cb[yr+1]--;
while (i<n&&i<xr) i+=L;
}
}
} ll ans; int main()
{
F(i,2,maxn-1) _log2[i]=_log2[i>>1]+1;
scanf("%d",&t);
while (t--)
{
ans=0;
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(ca,0,sizeof ca);
memset(cb,0,sizeof cb);
scanf("%s",s);
n=strlen(s);
F(i,0,n-1)
{
SA.s[i]=s[i]-'a'+1;
SB.s[i]=s[n-i-1]-'a'+1;
}
SA.s[n]=SB.s[n]=0;
SA.build(n,30); SB.build(n,30);
F(i,1,n) solve(i);
a[0]=ca[0]; b[0]=cb[0];
F(i,1,n) a[i]=a[i-1]+ca[i],b[i]=b[i-1]+cb[i];
F(i,0,n) ans+=(ll)a[i]*b[i];
printf("%lld\n",ans);
}
}
BZOJ 4650 [Noi2016]优秀的拆分 ——后缀数组的更多相关文章
- BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)
BZOJ 洛谷 令\(st[i]\)表示以\(i\)为开头有多少个\(AA\)这样的子串,\(ed[i]\)表示以\(i\)结尾有多少个\(AA\)这样的子串.那么\(Ans=\sum_{i=1}^{ ...
- BZOJ 4650 [Noi2016]优秀的拆分:后缀数组
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4650 题意: 给你一个字符串s,问你s及其子串中,将它们拆分成"AABB&quo ...
- [NOI2016]优秀的拆分 后缀数组
题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...
- [BZOJ]4650: [Noi2016]优秀的拆分
Time Limit: 30 Sec Memory Limit: 512 MB Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串, ...
- 【刷题】BZOJ 4650 [Noi2016]优秀的拆分
Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆分是优秀的.例如,对于字符串 aabaabaa,如果令 A ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...
- [NOI2016]优秀的拆分(SA数组)
[NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...
- UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]
#219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...
- NOI 2016 优秀的拆分 (后缀数组+差分)
题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...
随机推荐
- codevs 3278 最小m 段和问题
时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给定 n 个整数(不一定是正整数)组成的序列,现在要求将序列分割为 m 段,每段 ...
- JavaScript实现的水果忍者游戏,支持鼠标操作
智能手机刚刚普及时,水果忍者这款小游戏可谓风靡一时.几年过去了,现在,让我们用纯JavaScript来实现这个水果忍者游戏,就算是为了锤炼我们的JavaScript开发技能吧. 大家可以通过这个链接在 ...
- Mybatis Cache 缓存策略
Mybatis Cache 缓存策略 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用 ...
- JS对输入判断变化屏蔽中文输入法输入时连续触发事件的方法
代码如下: //智能搜索提示 IntelligenceSearch: function IntelligenceSearch() { $('#keyWord').on('input', functio ...
- vue的使用-项目总结
1,这是一个重前端逻辑,轻交互,数据展示的项目,可读性差,2,组件划分的坑,复用过多的坑,复用过多导致要在js手动判断太多东西,不便于可读3,vuex的坑,数据分为后台请求数据的暂存,前端页面逻辑的状 ...
- https 调用验证失败 peer not authenticated
https 调用验证失败 peer not authenticated 报错日志: Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer ...
- baidumap demo(一)
覆盖物概述 地图上自定义的标注点和覆盖物我们统称为地图覆盖物.您可以通过定制BMKAnnotation和BMKOverlay来添加对应的标注点和覆盖物.地图覆盖物的设计遵循数据与View分离的原则,B ...
- UVa-156-反片语
这题比较精妙的是,我们对于单词重排,实际上是进行了标准化的处理,即按照字典序排序. 这样的话,就很方便地处理了单词的重排问题,我们不需要使用全排列函数进行排列尝试,我们直接化简为一,然后进行比较就可以 ...
- 【最短路径树】51nod1443 路径和树
并不是什么高端操作并且一些模型会用到 Description 给定一幅无向带权连通图G = (V, E) (这里V是点集,E是边集).从点u开始的最短路径树是这样一幅图G1 = (V, E1),其中E ...
- 【数论 dp】2048
考场上一个DFS优化乱加就对了一个无解的点 题目描述 给定一个长度为 n 的数列,在这个数列中选取一个子序列使得这个子序列中的数能合出2048 对于合并操作,可以选择这个序列中的任意两个数进行合并,当 ...