传送门

 
题解
  听说大佬们这题都是用SA秒掉的
  然而SA的时间复杂度的确很优秀,缺点就是看不太懂……
  然后发现一位大佬用哈希华丽的过了此题,而且讲的特别清楚->这里
  我们只要考虑以每一个点结尾的$AA$串的个数$u[i]$和以每一个点开头的AA串的个数$v[i]$,答案就是$\sum _{i=1}^{n-1} u[i]*v[i+1]$
  那么考虑如何求出$u$和$v$呢
  我们考虑一下,枚举串$A$的长度$len$,然后每隔$len$个单位设置一个关键点。不难发现,每一个长度为$len*2$的$AA$串,必定经过两个关键点
  然后考虑,只要求出相邻两个关键点往前的$LCS$和往后的$LCP$,如果$LCS+LCP>=len$,就表明存在长度为$len$的$AA$串。而且不难发现,所有经过这两个关键点的长度为$len$的$AA$串,肯定是连续的!所以我们可以找到这个区间,然后用前缀和差分,就可以避免区间修改了
  说了这么多,到底怎么求$LCS$和$LCP$呢?(大佬:SA+ST表不是随便过的么)嗯,没错,二分。我们二分它们的长度,然后用哈希判断是否相等。这样虽然时间复杂度比起ST表多了个$log$,但起码更看得懂……
  时间复杂度是枚举$len$的调和级数,加上二分,为$O(nlog^2n)$
  ps:话说我也不明白调和级数是个什么玩意儿,只要知道枚举的复杂度是$\sum _{i=1}^n \frac{n}{i} =O(nlogn)$就行了……
  pps:管那么多干嘛能A不就行了么……话说这题明明纯哈希暴力就有95……某大佬讲课的时候还以这题为例嘲笑NOI近几年的出题水平(逃)
 //minamoto
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=,mod=3e7+;
char s[N];int n;
ll hash[N],mo[N],u[N],v[N],ans;
inline ll gethash(int l,int r){
ll now=hash[l]-hash[r]*mo[r-l];
now%=mod,now+=mod,now%=mod;
return now;
}
int main(){
int T=read();mo[]=;for(int i=;i<=;++i) mo[i]=mo[i-]*%mod;
while(T--){
n=;char ch;
while((ch=getc())!='\n') s[++n]=ch;
memset(u,,sizeof(u)),memset(v,,sizeof(v));
hash[n+]=;
for(int i=n;i;--i) (hash[i]=hash[i+]*+s[i]-'a'+)%=mod;
for(int L=;L*<=n;++L){
for(int i=L<<;i<=n;i+=L){
if(s[i]!=s[i-L]) continue;
int l=,r=L,last=i-L,pos=;
//二分查找lcp和lcs
while(l<=r){
int mid=l+r>>;
if(gethash(last-mid+,last+)==gethash(i-mid+,i+)) pos=mid,l=mid+;
else r=mid-;
}
int head=i-pos+;
l=,r=L,pos=;
while(l<=r){
int mid=l+r>>;
if(gethash(last,last+mid)==gethash(i,i+mid)) pos=mid,l=mid+;
else r=mid-;
}
int tail=i+pos-;
head=max(head+L-,i);//防止越过两块
tail=min(tail,i+L-);//防止跑到后面的块
if(head<=tail){
++u[head-*L+],--u[tail+-*L+];
++v[head],--v[tail+];
//为了差分
//因为head-2*L+1到tail-2*L+1开头的AA串增加的
//以他们的答案都可以++
//然后以head到tail结尾的AA串也++
}
}
}
ans=;
for(int i=;i<=n;++i) u[i]+=u[i-],v[i]+=v[i-];
for(int i=;i<n;++i) ans+=v[i]*u[i+];
print(ans);
}
Ot();
return ;
}
 
 

[BZOJ]4650 优秀的拆分(Noi2016)(哈希+二分)的更多相关文章

  1. [BZOJ]4650 优秀的拆分(Noi2016)

    比较有意思的一道后缀数组题.(小C最近是和后缀数组淦上了?) 放在NOI的考场上.O(n^3)暴力80分,O(n^2)暴力95分…… 即使想把它作为一道签到题也不要这么随便啊摔(╯‵□′)╯︵┻━┻ ...

  2. 【洛谷1117_BZOJ4650】[NOI2016] 优秀的拆分(哈希_后缀数组_RMQ)

    题目: 洛谷1117 分析: 定义把我校某兔姓神犇Tzz和他的妹子拆分,为"优秀的拆分" 随便写个哈希就能有\(95\)分的好成绩-- 我的\(95\)分做法比fei较chang奇 ...

  3. bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...

  4. LOJ2083 [NOI2016] 优秀的拆分 【哈希】【调和级数】

    题目分析: 好题!我们发现题目实际是要求出从某个左端点开始跑出去的BB型有多少个和从某个右端点开始跑出去的AA型有多少个. 发现这个问题是对称的,所以只考虑从左端点跑出去的BB型有多少个就可以了. 我 ...

  5. loj2083 优秀的拆分 [NOI2016] SA

    正解:SA 解题报告: 我永远喜欢loj! 显然$AABB$串相当于是由两个$AA$串拼起来的,所以可以先考虑如果求出来了所有$AA$串怎么求答案? 就假如能统计出$st[i]$表示所有以$i$为开头 ...

  6. BZOJ 3796 Mushroom追妹纸 哈希+二分(+KMP)

    先把两个串能匹配模式串的位置找出来,然后标记为$1$(标记在开头或末尾都行),然后对标记数组求一个前缀和,这样可以快速查到区间内是否有完整的一个模式串. 然后二分子串(答案)的长度,每次把长度为$md ...

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

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

  8. [BZOJ]4650: [Noi2016]优秀的拆分

    Time Limit: 30 Sec  Memory Limit: 512 MB Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串, ...

  9. 【刷题】BZOJ 4650 [Noi2016]优秀的拆分

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

随机推荐

  1. k8s v1.5.8 单节点搭建

    setsid etcd -name etcd -data-dir /var/lib/etcd -listen-client-urls http://0.0.0.0:2379,http://0.0.0. ...

  2. [bzoj2648]SJY摆棋子(带插入kd-tree)

    解题关键:带插入kdtree模板题. #include<iostream> #include<cstdio> #include<cstring> #include& ...

  3. 通过args数组获取数据

    ----------siwuxie095                     通过 main 方法的 args数组 可以从控制台获取一组字符串数据     如:     package com.s ...

  4. freemaker优缺点

    1.什么是FreeMarker?FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写.FreeMarker被设计用来生成HTMLWeb页面,特别是基于MVC模式的 ...

  5. bash 环境配置及脚本

    bash是 Bourne Again Shell简称 ,从unix系统的sh发展而来 查看当前shellecho $SHELL查看系统支持的shellcat /etc/shells cd /binls ...

  6. 1 Python入门及计算机硬件知识

    一: Python是一种编程语言 语言: 语言是一种事物与另外一种事物沟通的介质 所以说编程语言是程序员和计算机之间实现沟通的桥梁 什么是编程?: 编程就是程序员用计算机所能理解的表达方式(编程语言) ...

  7. windows server2012如何开启mysql远程登录

    开发的首要任务就是要搭建起自己的服务器,下面主要是我这搭建记录下 我的各种环境 服务器为Windows server2012  安装的MySQL数据的版本是5.6.10 ,64位.当然了版本对于安装没 ...

  8. [GO]使用map生成 json

    package main import ( "encoding/json" "fmt" ) func main() { m := make(map[) //因为 ...

  9. Thrift辅助类,用于简化Thrift编程

    CThriftServerHelper用于服务端,CThriftClientHelper用于客户端. IDL定义: service PackageManagerService { } 服务端使用示例: ...

  10. mybatis 输入、输出映射

    一.输入映射 mapper.xml的参数只有一个.可以传参数,基本简单类型,hashmap和javabean (一).Javabean的方法. 需求:通过小说名和作者模糊找书. 1.定义Javabea ...