原文链接http://www.cnblogs.com/zhouzhendong/p/9026184.html

题目传送门 - Codeforces 802I

题意

  求一个串中,所有本质不同子串的出现次数的平方和。

  $|s|\leq 10^5$

题解

  首先,这一题用 SAM 做就是模板题,比较简单。

  但是,本着练一练 SA 的心态,我开始了 SA+单调栈 的苦海。

  真毒瘤。

  这里讲一讲 SA 的做法,也是经典的做法。

   SA 闭着眼睛先写了再说。

  首先,我们考虑出现次数大于 $1$ 次的子串。

  考虑按照$SA$数组的顺序来进行处理,这样得到的后缀的字典序不断变大。

  如果要统计一个串与前一个串的 LCP 出现了多少次,该如何统计?

  显然是往前和往后都找到第一个 LCP 比当前小的停止并统计。

  于是我们用单调栈来维护一个 $height$ 升序的序列。具体的统计方法这里不多赘述,可以直接查阅代码。比较明了。

  单调栈要注意处理当前 LCP 和栈顶 LCP 长度值相同的情况。

  考虑只出现一次的串个数。对于第 $i$ 大的后缀(即 $SA[i]$ ),之前统计到的是 $SA[i]$ 与 $SA[i-1]$ 、$SA[i]$ 与 $SA[i+1] $ 的 LCP 的 $\max$ 。于是没用统计到的就是剩下的。于是当前后缀出现依次的串对答案的贡献就是 $len-\max$ 。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int T,n,m,SA[N],rank[N],height[N],tmp[N],tax[N];
char s[N];
int st[N],top,pos[N];
void Sort(int n,int m){
for (int i=0;i<=m;i++)
tax[i]=0;
for (int i=1;i<=n;i++)
tax[rank[i]]++;
for (int i=1;i<=m;i++)
tax[i]+=tax[i-1];
for (int i=n;i>=1;i--)
SA[tax[rank[tmp[i]]]--]=tmp[i];
}
bool cmp(int rk[],int x,int y,int w){
return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
}
void Suffix_Array(char s[],int n){
memset(SA,0,sizeof SA);
memset(tmp,0,sizeof tmp);
memset(rank,0,sizeof rank);
memset(height,0,sizeof height);
for (int i=1;i<=n;i++)
rank[i]=s[i],tmp[i]=i;
m=127;
Sort(n,m);
for (int w=1,p=0;p<n;w<<=1,m=p){
p=0;
for (int i=n-w+1;i<=n;i++)
tmp[++p]=i;
for (int i=1;i<=n;i++)
if (SA[i]>w)
tmp[++p]=SA[i]-w;
Sort(n,m);
swap(rank,tmp);
rank[SA[1]]=p=1;
for (int i=2;i<=n;i++)
rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;
}
for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)
for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%s",s+1);
n=strlen(s+1);
Suffix_Array(s,n);
LL ans=0;
top=0;
memset(st,0,sizeof st);
memset(pos,0,sizeof pos);
SA[n+1]=height[0]=0;
for (int i=2;i<=n+1;i++){
int nowpos=i,len=height[i];
while (top>0&&st[top]>len){
LL v1=st[top]-max(st[top-1],len);
LL v2=i-pos[top]+1;
ans+=v1*v2*v2;
nowpos=pos[top--];
}
while (top>0&&st[top]==len)
nowpos=pos[top--];
st[++top]=len;
pos[top]=nowpos;
}
for (int i=1;i<=n;i++)
ans+=n-i+1-max(height[rank[i]],height[rank[i]+1]);
printf("%I64d\n",ans);
}
return 0;
}

  

Codeforces 802I Fake News (hard) (SA+单调栈) 或 SAM的更多相关文章

  1. Codeforces 873F Forbidden Indices 字符串 SAM/(SA+单调栈)

    原文链接https://www.cnblogs.com/zhouzhendong/p/9256033.html 题目传送门 - CF873F 题意 给定长度为 $n$ 的字符串 $s$,以及给定这个字 ...

  2. Codeforces 1073G Yet Another LCP Problem $SA$+单调栈

    题意 给出一个字符串\(s\)和\(q\)个询问. 每次询问给出两个长度分别为\(k,l\)的序列\(a\)和序列\(b\). 求\(\sum_{i=1}^{k}\sum_{j=1}^{l}lcp(s ...

  3. Codeforces 1107G Vasya and Maximum Profit [单调栈]

    洛谷 Codeforces 我竟然能在有生之年踩标算. 思路 首先考虑暴力:枚举左右端点直接计算. 考虑记录\(sum_x=\sum_{i=1}^x c_i\),设选\([l,r]\)时那个奇怪东西的 ...

  4. luogu2178/bzoj4199 品酒大会 (SA+单调栈)

    他要求的就是lcp(x,y)>=i的(x,y)的个数和a[x]*a[y]的最大值 做一下后缀和,就只要求lcp=i的了 既然lcp(x,y)=min(h[rank[x]+1],..,[h[ran ...

  5. BZOJ3238 [Ahoi2013]差异 SA+单调栈

    题面 戳这里 题解 考虑把要求的那个东西拆开算,前面一个东西像想怎么算怎么算,后面那个东西在建出\(height\)数组后相当于是求所有区间\(min\)的和*2,单调栈维护一波即可. #includ ...

  6. poj 3415 Common Substrings【SA+单调栈】

    把两个串中间加一个未出现字符接起来,然后求SA 然后把贡献统计分为两部分,在排序后的后缀里,属于串2的后缀和排在他前面属于串1的后缀的贡献和属于串1的后缀和排在他前面属于串2的后缀的贡献 两部分分别作 ...

  7. codeforces 817 D. Imbalanced Array(单调栈+思维)

    题目链接:http://codeforces.com/contest/817/problem/D 题意:给你n个数a[1..n]定义连续子段imbalance值为最大值和最小值的差,要你求这个数组的i ...

  8. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

  9. Educational Codeforces Round 23 D. Imbalanced Array 单调栈

    D. Imbalanced Array time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

随机推荐

  1. mysql设计表时注意事项

    说明:本文是对项目过程中的一些要求的简单汇总整理,主要是供个人本身参考... 一.表设计 1. 在创建表结构时,表名.字段需要见名知意,不采用拼音 create table  `tb_abc` (   ...

  2. 接口签名进行key排序,并MD5加密

    import org.apache.commons.codec.digest.DigestUtils; import java.io.UnsupportedEncodingException; imp ...

  3. Python 生产者与消费者模型

    定义: 在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度.     为什么要使用生产者和消费者模式 在线程世界里,生 ...

  4. SwipeRefreshLayout,用最少的代码定制最美的上下拉刷新样式

    下拉刷新框架其实有很多,而且质量都比较高.但是在日常开发中,每一款产品都会有一套自己独特的一套刷新样式.相信有很多小伙伴在个性化定制中都或多或少的遇到过麻烦.今天我就给大家推荐一个在定制方面很出彩的一 ...

  5. Ajax中onreadystatechange函数不执行,是因为放在open()后

    今天动手写Ajax时遇到的问题:按照下面的顺序来写Ajax,功能是alert出txt文档的内容,在Chrome下可以执行onreadystatechange中的事件,在IE11及以下.FF就不能执行o ...

  6. Confluence 6 内存使用和需求

    管理 Confluence 性能和内存的使用和有什么资源可用是密切相关的.如果你给 Confluence 更多的内存来缓存内容,Confluence 将会运行得更加迅速,但是相对比较低的内存环境中,C ...

  7. Confluence 6 数据库结构图

    结构图细节 下面的 SVG 图片(可缩放矢量图)包括了 Confluence 数据库中使用的所有表.单击下面的连接在你的浏览器中打开图片连接,你也可以随后将图片下载到本地.你可以使用浏览器的缩放快捷键 ...

  8. STL 容器区别:vector、list、deque、set、map的底层实现

    https://blog.csdn.net/shawjan/article/details/45424405

  9. CentOS7图形界面与命令行界面切换(转载)

    在图形界面使用 ctrl+alt+F2切换到dos界面 dos界面 ctrl+alt+F2切换回图形界面 在命令上 输入 init 3 命令 切换到dos界面 输入 init 5命令 切换到图形界面 ...

  10. lightoj1234 打表技巧:分块打表

    /* 打不了那么大的表,所以只记录分块的信息即可 */ #include<bits/stdc++.h> using namespace std; #define maxn 1000005 ...