BZOJ3238: [Ahoi2013]差异 (后缀自动机)
Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
Sample Output
HINT
2<=N<=500000,S由小写英文字母组成
YY了后缀自动机的解法:
首先题意就是让你求sigma(LCP(i,j)|i<j)
将字符串反过来,考虑两个后缀对答案的贡献,其实就是节点x和y的lca节点包含的最长子串长度
那么将SAM构出来,考虑当LCA为节点z时,有多少满足条件的(x,y),这个枚举z的相邻子节点,dp一下即可
code:O(n) 2104ms
- #include<cstdio>
- #include<cctype>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- typedef long long LL;
- const int maxn=;
- int n,to[maxn][],fa[maxn],l[maxn],f[maxn],x[maxn],w[maxn],od[maxn],cnt=,last=;
- void extend(int c)
- {
- int p,q,np,nq;
- p=last;last=np=++cnt;l[np]=l[p]+;f[np]=w[np]=;
- for(;!to[p][c];p=fa[p]) to[p][c]=np;
- if(!p) fa[np]=;
- else
- {
- q=to[p][c];
- if(l[p]+==l[q]) fa[np]=q;
- else
- {
- nq=++cnt;l[nq]=l[p]+;
- memcpy(to[nq],to[q],sizeof(to[q]));
- fa[nq]=fa[q];
- fa[q]=fa[np]=nq;
- for(;to[p][c]==q;p=fa[p]) to[p][c]=nq;
- }
- }
- }
- LL solve()
- {
- LL ans=;
- for(int i=;i<=cnt;i++) x[l[i]]++;
- for(int i=;i<=n;i++) x[i]+=x[i-];
- for(int i=;i<=cnt;i++) od[x[l[i]]--]=i;
- for(int i=cnt;i;i--) f[fa[od[i]]]+=f[od[i]];
- for(int i=;i<=cnt;i++)
- {
- ans+=(LL)w[fa[i]]*f[i]*l[fa[i]];
- w[fa[i]]+=f[i];
- }
- return ans;
- }
- char s[maxn];
- int main()
- {
- scanf("%s",s);
- n=strlen(s);
- for(int i=n-;i>=;i--) extend(s[i]-'a');
- LL ans=;
- for(int i=;i<=n;i++) ans+=(LL)i*(n-);
- printf("%lld\n",ans-*solve());
- return ;
- }
另外转一下hzwer的SA解法:
--------------------------------------------------------------------------------------------------------------------------------------------蒟蒻与神犇的分界线--------------------------------------------
显然后缀数组不是正确姿势。。。
不过还是说说后缀数组的做法吧,bzoj总时限20s是能过的
SA+rmq求lcp应该烂大街了,这题还不用rmq。。。
首先求出h数组
考虑h[i]在哪些区间内会成为最小值,这个用两次单调栈很容易就能解决
还要处理一下由于h[i]可能相同造成的重复计数问题,具体看代码
code O(nlogn) 13592ms
- #include<set>
- #include<map>
- #include<ctime>
- #include<queue>
- #include<cmath>
- #include<cstdio>
- #include<vector>
- #include<cstring>
- #include<cstdlib>
- #include<iostream>
- #include<algorithm>
- #define N 500005
- #define inf 1000000000
- #define pa pair<int,int>
- #define ll long long
- using namespace std;
- ll ans;
- int n,k,p,q=,top;
- int v[N],a[N],h[N],sa[][N],rk[][N];
- int st[N],l[N],r[N];
- char ch[N];
- void mul(int *sa,int *rk,int *SA,int *RK)
- {
- for(int i=;i<=n;i++)v[rk[sa[i]]]=i;
- for(int i=n;i;i--)
- if(sa[i]>k)
- SA[v[rk[sa[i]-k]]--]=sa[i]-k;
- for(int i=n-k+;i<=n;i++)SA[v[rk[i]]--]=i;
- for(int i=;i<=n;i++)
- RK[SA[i]]=RK[SA[i-]]+(rk[SA[i-]]!=rk[SA[i]]||rk[SA[i-]+k]!=rk[SA[i]+k]);
- }
- void presa()
- {
- for(int i=;i<=n;i++)v[a[i]]++;
- for(int i=;i<=;i++)v[i]+=v[i-];
- for(int i=;i<=n;i++)sa[p][v[a[i]]--]=i;
- for(int i=;i<=n;i++)
- rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i-]]!=a[sa[p][i]]);
- for(k=;k<n;k<<=,swap(p,q))
- mul(sa[p],rk[p],sa[q],rk[q]);
- for(int k=,i=;i<=n;i++)
- {
- int j=sa[p][rk[p][i]-];
- while(ch[j+k]==ch[i+k])k++;
- h[rk[p][i]]=k;if(k>)k--;
- }
- }
- void solve()
- {
- for(int i=;i<=n;i++)ans+=(ll)i*(n-);
- h[]=-inf;
- for(int i=;i<=n;i++)
- {
- while(h[i]<=h[st[top]])top--;
- if(st[top]==)l[i]=;
- else l[i]=st[top]+;
- st[++top]=i;
- }
- h[n+]=-inf;top=;st[]=n+;
- for(int i=n;i;i--)
- {
- while(h[i]<h[st[top]])top--;
- if(st[top]==n+)r[i]=n;
- else r[i]=st[top]-;
- st[++top]=i;
- }
- for(int i=;i<=n;i++)
- ans-=2LL*(i-l[i]+)*(r[i]-i+)*h[i];
- }
- int main()
- {
- scanf("%s",ch+);
- n=strlen(ch+);
- for(int i=;i<=n;i++)a[i]=ch[i]-'a'+;
- presa();
- solve();
- printf("%lld",ans);
- return ;
- }
BZOJ3238: [Ahoi2013]差异 (后缀自动机)的更多相关文章
- [bzoj3238][Ahoi2013]差异——后缀自动机
Brief Description Algorithm Design 下面给出后缀自动机的一个性质: 两个子串的最长公共后缀,位于这两个串对应的状态在parent树上的lca状态上.并且最长公共后缀的 ...
- BZOJ3238: [Ahoi2013]差异(后缀自动机)
题意 题目链接 Sol 前面的可以直接算 然后原串翻转过来,这时候变成了求任意两个前缀的最长公共后缀,显然这个值应该是\(len[lca]\),求出\(siz\)乱搞一下 #include<bi ...
- BZOJ 3238: [Ahoi2013]差异 [后缀自动机]
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2512 Solved: 1140[Submit][Status ...
- bzoj3238 [Ahoi2013]差异 后缀数组+单调栈
[bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...
- [Ahoi2013]差异(后缀自动机)
/* 前面的那一坨是可以O1计算的 后面那个显然后缀数组单调栈比较好写??? 两个后缀的lcp长度相当于他们在后缀树上的lca的深度 那么我们就能够反向用后缀自动机构造出后缀树然后统计每个点作为lca ...
- 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)
题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...
- BZOJ 3238 [Ahoi2013]差异 ——后缀自动机
后缀自动机的parent树就是反串的后缀树. 所以只需要反向构建出后缀树,就可以乱搞了. #include <cstdio> #include <cstring> #inclu ...
- [AHOI2013]差异 后缀自动机_Parent树
题中要求: $\sum_{1\leqslant i < j \leq n } Len(T_{i}) +Len(T_{j})-2LCP(T_{i},T_{j})$ 公式左边的部分很好求,是一个常量 ...
- BZOJ.3238.[AHOI2013]差异(后缀自动机 树形DP/后缀数组 单调栈)
题目链接 \(Description\) \(Solution\) len(Ti)+len(Tj)可以直接算出来,每个小于n的长度会被计算n-1次. \[\sum_{i=1}^n\sum_{j=i+1 ...
- BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp
http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...
随机推荐
- Linux 怎么查看服务的启动进程所占用的目录
lsof简介 lsof(list open files)是一个列出当前系统打开文件的工具.在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件.所以 ...
- javascript 重写已有的方法
现在有一个需求,需要重写方法,比如方法名为a,但是在方法内部,需要用到原来的方法,怎么办? 最直接的办法是: var b = a; window.a = function(args){ a.call( ...
- MySQL性能优化的最佳经验
今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据 ...
- VMware Snapshot 工作原理
VMware中的快照是对VMDK在某个时间点的“拷贝”,这个“拷贝”并不是对VMDK文件的复制,而是保持磁盘文件和系统内存在该时间点的状态,以便在出现故障后虚拟机能够恢复到该时间点.如果对某个虚拟机创 ...
- su成别的用户后仍以原来私钥访问远程机器
背景: 同步机和游戏服两台机都有个人用户账号和游戏账号xy1,游戏服设了xy1的ssh强制命令来受同步机的xy1控制.现在需要在同步机上用xy1进行一个控制游戏服的操作,该操作需要在同步机远程tail ...
- LightOJ 1234 Harmonic Number (打表)
Harmonic Number Time Limit:3000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Submi ...
- Light OJ 1296 - Again Stone Game (博弈sg函数递推)
F - Again Stone Game Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu ...
- (七)STM32的RTC简单操作
简单说明: /********************************************************************************************* ...
- GCM 发送接收消息 Message Client Server 服务器端,客户端
GCM 传递参数 最近用了很多时间做GCM,由于碰到很多问题,因此详细做一下记录,以方便各位网友,不用再走我的重复的路.不过我试了一下GCM在国内很不好用.假如开发国外的程序的话,用GCM倒是很不错的 ...
- .net学习笔记---Asp.net的生命周期之二页生命周期
用户请求 从 用户角度来说,我不管你后台经历了什么,我只想要我请求的页面.请求到服务器端,服务器必须得有所表示的是吧,即使不想搭理人家也得让IIS给人家说声:找不到服务器.请求来到服务器端,肯定要让服 ...