BZOJ4650 NOI2016优秀的拆分(后缀数组)
显然只要求出以每个位置开始的AA串数量就可以了,将其和反串同位置的结果乘一下,加起来就是答案。考虑对每种长度的字符串计数。若当前考虑的A串长度为x,我们每隔x个字符设一个关键点,求出相邻两关键点的后缀lcp和前缀lcs,交叉部分就是跨过这两个关键点的A串长度为x的AA串个数。差分一发就能对每个位置求了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 30010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int T,n,a[N],cnt[N],rk[][N<<],tmp[N<<],sa[N],sa2[N],f[][N][],h[N],lg2[N],ans[][N];
char s[N];
void make(int op)
{
int m=;
memset(cnt,,sizeof(cnt));memset(rk[op],,sizeof(rk[op]));
for (int i=;i<=n;i++) cnt[rk[op][i]=a[i]]++;
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[a[i]]--]=i;
for (int k=;k<=n;k<<=)
{
int p=;
for (int i=n-k+;i<=n;i++) sa2[++p]=i;
for (int i=;i<=n;i++) if (sa[i]>k) sa2[++p]=sa[i]-k;
memset(cnt,,sizeof(cnt));
for (int i=;i<=n;i++) cnt[rk[op][i]]++;
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[rk[op][sa2[i]]]--]=sa2[i];
memcpy(tmp,rk[op],sizeof(tmp));
p=;rk[op][sa[]]=;
for (int i=;i<=n;i++)
{
if (tmp[sa[i]]!=tmp[sa[i-]]||tmp[sa[i]+k]!=tmp[sa[i-]+k]) p++;
rk[op][sa[i]]=p;
}
if (p==n) break;
m=p;
}
for (int i=;i<=n;i++)
{
h[i]=max(h[i-]-,);
while (a[i+h[i]]==a[sa[rk[op][i]-]+h[i]]) h[i]++;
}
for (int i=;i<=n;i++) f[op][i][]=h[sa[i]];
for (int j=;j<;j++)
for (int i=;i<=n;i++)
f[op][i][j]=min(f[op][i][j-],f[op][min(n,i+(<<j-))][j-]);
for (int i=;i<=n;i++)
{
lg2[i]=lg2[i-];
if ((<<lg2[i])<=i) lg2[i]++;
}
}
int query(int x,int y,int op)
{
if (x>y) swap(x,y);
x++;if (x>y) return N;
return min(f[op][x][lg2[y-x+]],f[op][y-(<<lg2[y-x+])+][lg2[y-x+]]);
}
void solve(int op)
{
memset(ans[op],,sizeof(ans[op]));
for (int i=;i<=n;i++)
for (int j=i;j+i<=n;j+=i)
{
int x=j,y=j+i;
int lcp=query(rk[op][x+],rk[op][y+],op),lcs=query(rk[op^][n-x+],rk[op^][n-y+],op^);
lcp=min(lcp,i-),lcs=min(lcs,i);
if (lcp+lcs>=i) ans[op][x-lcs+]++,ans[op][x-lcs+(lcp+lcs-i)+]--;
}
for (int i=;i<=n;i++) ans[op][i]+=ans[op][i-];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4650.in","r",stdin);
freopen("bzoj4650.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
scanf("%s",s+);
n=strlen(s+);memset(a,,sizeof(a));
for (int i=;i<=n;i++) a[i]=s[i]-'a'+;
make();
for (int i=;i<=n;i++) a[i]=s[n-i+]-'a'+;
make();
solve(),solve();
ll tot=;
for (int i=;i<=n;i++) tot+=ans[][i]*ans[][n-i+];
cout<<tot<<endl;
}
return ;
}
BZOJ4650 NOI2016优秀的拆分(后缀数组)的更多相关文章
- [NOI2016]优秀的拆分  后缀数组
		
题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...
 - 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]至少两个点. 然后我们可以 ...
 - [UOJ#219][BZOJ4650][Noi2016]优秀的拆分
		
[UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...
 - [NOI2016]优秀的拆分(SA数组)
		
[NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...
 - BZOJ4650 [NOI2016]优秀的拆分  【后缀数组】
		
题目 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆 分是优秀的.例如,对于字符串 aabaabaa,如果令 A=aabA=aa ...
 - bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)
		
https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...
 - UOJ#219. 【NOI2016】优秀的拆分 [后缀数组 ST表]
		
#219. [NOI2016]优秀的拆分 题意:求有多少AABB样子的子串,拆分不同的同一个子串算多个 一开始一直想直接求,并不方便 然后看了一眼Claris的题解的第一行就有思路了 如果分开,求\( ...
 - UOJ#219/BZOJ4650 [NOI2016]优秀的拆分 字符串 SA ST表
		
原文链接http://www.cnblogs.com/zhouzhendong/p/9025092.html 题目传送门 - UOJ#219 (推荐,题面清晰) 题目传送门 - BZOJ4650 题意 ...
 
随机推荐
- C语言程序设计II—第四周教学
			
第四周教学总结(18/3-24/3) 教学内容 本周的教学内容为:第七章 数组 7.2 二维数组 课前准备 在博客园发布作业:2019春第四周作业 第三周作业讲解视频:A Programing Vid ...
 - 创建一个宽高成比例的弹性div盒子
			
这里先提供一种,有更好的方法再补充. demo代码如下: <!DOCTYPE html> <html lang="en"> <head> < ...
 - jQuery webcam plugin
			
jQuery webcam plugin The jQuery webcam plugin is a transparent layer to communicate with a camera di ...
 - VB6 变量定义作用域的一个奇特形式
			
C#或JAVA 下面的i定义是只会限定在if 条件块里的: if (1 == 2) { int i = 000; } else { i = 111;// 错误,未定义. } i = 222;//错误 ...
 - R实战 第十篇:列联表和频数表
			
列联表是观测数据按两个或更多属性(定性变量)分类时所列出的频数分布表,它是由两个以上的变量进行交叉分类的频数分布表.交互分类的目的是将两变量分组,然后比较各组的分布状况,以寻找变量间的关系. 按两个变 ...
 - Socket异步通信及心跳包同时响应逻辑分析(最后附Demo)。
			
有段时间没有更博了,刚好最近在做Socket通信的项目,原理大致内容:[二维码-(加logo)]-->提供主机地址和端口号信息(直接使用[ThoughtWorks.QRCode.dll]比较简单 ...
 - cgroup.conf系统初始配置
			
# Slurm cgroup support configuration file # # See man slurm.conf and man cgroup.conf for further # i ...
 - Python-dict-12
			
字典 Why:咱们目前已经学习到的容器型数据类型只有list,那么list够用?他有什么缺点呢? 1. 列表可以存储大量的数据类型,但是如果数据量大的话,他的查询速度比较慢. 2. 列表只能按照顺序存 ...
 - 四则运算    C 语言
			
#include<stdio.h>void main(){ char c; float x,y; int result; scanf("%c %f %f",&c ...
 - linux及安全第六周总结
			
进程控制块pcb——task_struct 操作系统三大功能: 进程管理(核心) 内存管理 文件系统 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息: 进程状态 ...