传送门

 
题解
  听说大佬们这题都是用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. Fedora下安装Scrapy遇到的两个问题

    error:/usr/lib/rpm/redhat/redhat-hardened-cc1: No such file or directory 需要安装redhat-rpm-config sudo ...

  2. 【UVA1515 算法竞赛入门指南】 水塘【最小割】

    题意: 输入一个h行w列的字符矩阵,草地用“#”表示,洞用"."表示.你可以把草改成洞,每格花费为d,也可以把洞填上草,每格花费为f.最后还需要在草和洞之间修围栏,每条边花费为b. ...

  3. 值得一做》关于一道暴搜BZOJ1024(EASY+)

    为什么要写这道题的DP捏? 原因很简单,因为为原来在openjudge上有一道题叫分蛋糕,有一个思路和这道题很像:“分锅”. 分锅:即为考虑计算当前情况的最优解时,把当前状态结果,分散为考虑当前状态的 ...

  4. sql设置字段默认值

    alter table 表名 modify 字段名 default 默认值;

  5. Hibernate多对多操作

    ---------------------siwuxie095 Hibernate 多对多操作 以用户和角色为例 (一)多对多映射配置 第一步:创建两个实体类,用户和角色 第二步:让两个实体类之间互相 ...

  6. @EnableAsync annotation metadata was not injected Spring容器启动后访问Servlet报错

    @EnableAsync annotation metadata was not injected 2015年12月20日 20:06:54 7570 在初始化spring事务部分碰到该错误, 详细错 ...

  7. 404. Sum of Left Leaves 左叶子之和

    [抄题]: Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are ...

  8. office excel 2010 破解版下载地址

    office excel 2010 破解版下载地址  http://www.xitongzhijia.net/soft/24189.html

  9. LA4794 分享巧克力

    Sharing Chocolate Chocolate in its many forms is enjoyed by millions of people around the world ever ...

  10. linux换行PHP_EOL

    $file = 'log.txt';file_put_contents($file,$param.PHP_EOL,FILE_APPEND);