传送门

 
题解
  听说大佬们这题都是用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. 数组和集合(二):List集合的使用总结

    一.概述 · 继承collection接口,List代表一个元素有序.且可重复(包括null)的集合,集合中的每个元素都有其对应的顺序索引 · List默认按元素的添加顺序设置元素的索引 · 提供了一 ...

  2. go unit test-monkey

    package main import ( "fmt" "github.com/bouk/monkey" "os" "os/exe ...

  3. 读书笔记 Week7 2018-4-19

    <构建之法> 第十二章 用户体验 读书笔记 首先不得不说,现如今大部分的电脑使用者,都被微软的图形化界面把口味养刁了.当然,包括我自己.无论是在微机原理上级的时候使用那些带着浓郁的上世纪八 ...

  4. Kafka总结的一张图

  5. MobileMovieTexture播放视频

    MobileMovieTexture插件支持IOS系统播放视频文件.简单,方便

  6. cs api测试

    更新磁盘方案 http://192.168.150.16:8900/client/api?command=updateDiskOffering&id=199e3be4-2af1-47a3-9f ...

  7. java解决跨域

    方法中response.setHeader("Access-Control-Allow-Origin", "https://ding.taozugong.com" ...

  8. js总结33 :javascript-DOM节点属性

    1 设置节点属性三个方法: 获取:getAttribute(名称) 设置:setAttribute(名称, 值) 删除:removeAttribute(名称) 举个例子: <!DOCTYPE h ...

  9. DES加密与解密控制台c++代码

    #include"stdafx.h" #include<stdio.h> #include<string.h> void main() { //声明变量 c ...

  10. google earth 中的飞行模拟器的键盘控制