搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷。

题目链接:http://hihocoder.com/problemset/problem/1413

这个题非常的劲!

首先可以发现,每次只变换一个字符为#,所以每次答案一定会得到相应的包含#的答案,而这个方案是可以直接计算出来的。

假设是$S[i]=$#则会得到$i*(N-i+1)$的子串数。

所以每次的答案可以表示为$sum[root]+i*(N-i+1)-ans[i]$,其中$ans[i]$表示严格经过$i$位置的本质不同的子串,严格的意义即这个本质不同的子串有且仅有一次,且经过$i$;

所以问题就转化为如何求出$ans[1..N]$

然后如何找到本质不同的经过$i$的子串,考虑利用后缀自动机;

问了 abclzr队长 ,可以考虑存出每个$Parent$树中的节点的$Right$集合,这样再进行递推,就可以搞出答案,但实际上并不需要存出全部的$Right$集合,只需要记录每个节点的$Right$集合的最左最右端点。

这样,对于一个子串是否严格跨越$i$,就可以利用右端-距离+1以及左端来判断是否严格跨越。

然后每个节点代表了多个子串,把这些子串一起处理,对答案的贡献就相当于是区间加上一个等差数列,对$ans[]$二阶差分后可以$O(N)$出解。

其实也可以用线段树/树状数组维护,树状数组需要差分,而且构造两个比较好写,线段树只要支持区间加,单点加,区间和即可。

给出一下官方题解:

Code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 600010
int N;
char S[MAXN];
namespace SAM
{
int son[MAXN<<][],par[MAXN<<],len[MAXN<<],size[MAXN<<],l[MAXN<<],r[MAXN<<];
int root,last,sz;
#define INF 0x7fffffff
inline void Init() {root=last=sz=;}
inline void Extend(int c)
{
int cur=++sz,p=last;
len[cur]=len[p]+; size[cur]=;
while (p && !son[p][c]) son[p][c]=cur,p=par[p];
if (!p) par[cur]=root;
else
{
int q=son[p][c];
if (len[p]+==len[q]) par[cur]=q;
else
{
int nq=++sz; l[nq]=INF,r[nq]=;
memcpy(son[nq],son[q],sizeof(son[nq]));
par[nq]=par[q]; len[nq]=len[p]+;
while (p && son[p][c]==q) son[p][c]=nq,p=par[p];
par[cur]=par[q]=nq;
}
}
l[cur]=r[cur]=len[cur];
last=cur;
}
inline void Build() {Init(); for (int i=; i<=N; i++) Extend(S[i]-'a'+);}
int st[MAXN],id[MAXN<<];
LL sum[MAXN<<],ans[MAXN];
inline void Pre()
{
for (int i=; i<=sz; i++) st[len[i]]++;
for (int i=; i<=N; i++) st[i]+=st[i-];
for (int i=; i<=sz; i++) id[st[len[i]]--]=i;
for (int i=sz; i>=; i--)
{
int x=id[i];
l[par[x]]=min(l[par[x]],l[x]);
r[par[x]]=max(r[par[x]],r[x]);
for (int j=; j<=; j++)
sum[x]+=sum[son[x][j]];
sum[x]++;
}
sum[root]--;
for (int i=sz; i>=; i--)
{
int x=id[i];
if (r[x]-len[x]+<=l[x])
{
int L=r[x]-len[x]+,R=min(r[x]-len[par[x]],l[x]),Len=R-L+;
if (L<=R) ans[L]++,ans[R+]-=Len+,ans[R+]+=Len;
L=R+,R=l[x];
if (L<=R) ans[L]+=Len,ans[L+]-=Len,ans[R+]-=Len,ans[R+]+=Len;
}
}
for (int i=; i<=N; i++) ans[i]+=ans[i-];
for (int i=; i<=N; i++) ans[i]+=ans[i-];
// printf("%d\n",sum[root]);
}
}using namespace SAM;
int main()
{
scanf("%d%s",&N,S+);
SAM::Build(); SAM::Pre();
for (int i=; i<=N; i++) printf("%lld ",(LL)i*(N-i+)+sum[root]-ans[i]);
return ;
}
/*
10
abcabcabdc
*/

hihocoder challenge 24 C

【hihocoder#1413】Rikka with String 后缀自动机 + 差分的更多相关文章

  1. #1413 : Rikka with String 后缀自动机 + 二级差分

    http://hihocoder.com/problemset/problem/1413?sid=1199641 这题断断续续做了2个多星期吧,一直不会 设总答案为sum,替换后新加的子串数量为x,失 ...

  2. [TJOI2019]甲苯先生和大中锋的字符串——后缀自动机+差分

    题目链接: [TJOI2019]甲苯先生和大中锋的字符串 对原串建后缀自动机并维护$parent$树上每个点的子树大小,显然子树大小为$k$的节点所代表的子串出现过$k$次,那么我们需要将$[len[ ...

  3. HDU 6086 Rikka with String AC自动机 + DP

    Rikka with String Problem Description As we know, Rikka is poor at math. Yuta is worrying about this ...

  4. 牛客多校第四场 I string 后缀自动机/回文自动机

    这个回文自动机的板有问题,它虽然能过这道题,但是在计算size的时候会出锅! 题意: 求一个字符串中本质不同的连续子串有几个,但是某串和它反转后的字符串算一个. 题解: 要注意的是,一般字符串题中的“ ...

  5. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  6. Codeforces 917F Substrings in a String - 后缀自动机 - 分块 - bitset - KMP

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一个字母串,要求支持以下操作: 修改一个位置的字母 查询一段区间中,字符串$s$作为子串出现的次数 Solution 1 Bitset 每 ...

  7. 识别子串 (string)——后缀自动机+线段树

    题目 [题目描述] 一般地,对于一个字符串 S,和 S 中第 $ i $ 个字符 x,定义子串 $ T=S(i.j) $ 为一个关于 x 的识别子申,当且仅当: 1.$ i \leq x \leq j ...

  8. cf1121F. Compress String(后缀自动机)

    题意 题目链接 Sol 居然出个SAM板子也是没谁了233 #include<bits/stdc++.h> #define Pair pair<int, int> #defin ...

  9. hihoCoder #1646 : Rikka with String II(容斥原理)

    题意 给你 \(n\) 个 \(01\) 串 \(S\) ,其中有些位置可能为 \(?\) 表示能任意填 \(0/1\) .问对于所有填法,把所有串插入到 \(Trie\) 的节点数之和(空串看做根节 ...

随机推荐

  1. 《连载 | 物联网框架ServerSuperIO教程》- 9. 协议过滤器,解决一包多发、粘包、冗余数据

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  2. Lind.DDD.SSO单点登陆组件的使用(原创)

    回到目录 一般sso的说明 在Lind.DDD框架里,有对单点登陆的集成,原理就是各个网站去sso网站统一登陆授权,之后在sso网站将登陆的token进行存储,存储方式随你(cache,redis,m ...

  3. Atitit 游戏的原理与概论attilax总结

    Atitit 游戏的原理与概论attilax总结 1. 游戏历史2 1.1.1. 盘点PC游戏史上最重要的50款游戏2 1.1.2. 回味人类文明进程 五款经典的历史游戏2 2. 游戏类型(主要分为6 ...

  4. JS获取当前时间

    setInterval("getTime();", 1000); function getTime() { //document.getElementById('linkweb') ...

  5. 仿QQ空间根据位置弹出PopupWindow显示更多操作效果

    我们打开QQ空间的时候有个箭头按钮点击之后弹出PopupWindow会根据位置的变化显示在箭头的上方还是下方,比普通的PopupWindow弹在屏幕中间显示好看的多. 先看QQ空间效果图:       ...

  6. win7 由ie8升级ie11时安装不成功的一个原因

    纯净win7系统更新好补丁好 升级ie一直提示不成功,之前重来没有遇到过.官方提示的解决办法: https://support.microsoft.com/zh-cn/kb/2872074 根据内容初 ...

  7. UICollectionView布局cell的三种方式

    UICollectionViewFlowLayout里面: // 方法一 - (void)prepareLayout{} // 方法二 - (nullable NSArray<__kindof ...

  8. android 自定义控件——(四)圆形进度条

    ----------------------------------↓↓圆形进度条(源代码下有属性解释)↓↓---------------------------------------------- ...

  9. Augularjs-起步

    今年项目的需要,开始琢磨研究前端开发,由于之前项目已经用Angularjs了,就顺其而然的继续沿用. 在使用Angularjs之前,先要准备好工具:Nodejs.npm.git.bower.fis 下 ...

  10. Hash 函数及其重要性

    不时会爆出网站的服务器和数据库被盗取,考虑到这点,就要确保用户一些敏感数据(例如密码)的安全性.今天,我们要学的是 hash 背后的基础知识,以及如何用它来保护你的 web 应用的密码. 申明 密码学 ...