[HihoCoder1413]Rikka with String
题意
给你一个串,问你把每个位置的字符替换成#后串中有多少本质不同的子串。
\(n\le 3*10^5\)
sol
首先可以计算出原串里面有多少本质不同的子串。显然就是\(\sum_{i=1}^{tot}len_i-len_{fa_i}\)。
然后考虑把\(i\)位置替换成了#,那么你从\(1..i\)中任选左端点,\(i..n\)中任选右端点,这样的子串一定会是本质不同的。(一定含有字符#,满足长度不同或#的出现位置不同)
所以对于位置\(i\),答案先加上\(i*(n-i+1)\)。
然后也可以再给答案加上原有的本质不同的子串数目,这样我们就只需要求出:把\(i\)位置改成#后有多少本质不同的子串不再出现了(被砍断)。
考虑一个\(SAM\)中的状态\(i\),设其最大长度\(len_i\),\(right\)集合中的最小最大元素分别为\(l_i,r_i\)。
对于区间\([r_i-len_i+1,\min(r_i-len_{fa_i},l_i)]\)(如果合法的话),我们会给这个区间加上一个首项是\(1\)公差也是\(1\)的等差数列。
因为这个状态\(i\)本身是表示了\(len_i-len_{fa_i}+1\)个连续长度的子串,所以在这个区间内每向右移动一下就会有一个子串被砍断,因此是一个公差为\(1\)的等差数列。
对于区间\([min(r_i-len_{fa_i},l_i)+1,l_i]\)(如果合法的话),一旦#出现在这个区间里那么\(i\)这个状态表示的所有长度大于等于一定值的子串就都会被砍断。所以给这个区间集体加上前一个区间的长度,即\(\min(r_i-len_{fa_i},l_i)-(r_i-len_i+1)+1\)。
等差数列用二阶差分维护一下就可以了,注意原一阶差分(第二种情况就是一个一阶差分)对应的二阶差分。所以构出\(SAM\)后的复杂度可以做到线性。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 6e5+5;
int n,last=1,tot=1,tr[N][26],fa[N],len[N],l[N],r[N],t[N],a[N];
char s[N];long long sum,ans[N];
void extend(int c)
{
int v=last,u=++tot;last=u;
len[u]=len[v]+1;
while (v&&!tr[v][c]) tr[v][c]=u,v=fa[v];
if (!v) fa[u]=1;
else{
int x=tr[v][c];
if (len[x]==len[v]+1) fa[u]=x;
else{
int y=++tot;
memcpy(tr[y],tr[x],sizeof(tr[y]));
fa[y]=fa[x];fa[x]=fa[u]=y;len[y]=len[v]+1;
while (v&&tr[v][c]==x) tr[v][c]=y,v=fa[v];
}
}
}
int main()
{
scanf("%d",&n);scanf("%s",s+1);
memset(l,63,sizeof(l));
for (int i=1;i<=n;++i) extend(s[i]-'a'),l[last]=r[last]=i;
for (int i=1;i<=tot;++i) ++t[len[i]];
for (int i=1;i<=tot;++i) t[i]+=t[i-1];
for (int i=1;i<=tot;++i) a[t[len[i]]--]=i;
for (int i=tot;i;--i)
{
l[fa[a[i]]]=min(l[fa[a[i]]],l[a[i]]);
r[fa[a[i]]]=max(r[fa[a[i]]],r[a[i]]);
sum+=len[i]-len[fa[i]];
}
for (int i=2;i<=tot;++i)
{
int L=r[i]-len[i]+1,R=min(r[i]-len[fa[i]],l[i]),Len=R-L+1;
if (L<=R) ans[L]+=1,ans[R+1]-=Len+1,ans[R+2]+=Len;
L=R+1;R=l[i];
if (L<=R) ans[L]+=Len,ans[L+1]-=Len,ans[R+1]-=Len,ans[R+2]+=Len;
}
for (int i=1;i<=n;++i) ans[i]+=ans[i-1];
for (int i=1;i<=n;++i) ans[i]+=ans[i-1];
for (int i=1;i<=n;++i) printf("%lld ",1ll*i*(n-i+1)+sum-ans[i]);
puts("");return 0;
}
[HihoCoder1413]Rikka with String的更多相关文章
- 「hihocoder1413 Rikka with String」
题目 哈哈哈哈哈哈哈哈哈哈我还没自闭 好像前后调了两天了 哈哈哈哈哈哈哈哈哈哈我还没自闭 这道题就是给定一个小写字母串,回答分别把每个位置上的字符替换为\(#\)后的本质不同的子串数 首先就是跨过这个 ...
- 【Hihocoder1413】Rikka with String(后缀自动机)
[Hihocoder1413]Rikka with String(后缀自动机) 题面 Hihocoder 给定一个小写字母串,回答分别把每个位置上的字符替换为'#'后的本质不同的子串数. 题解 首先横 ...
- hdu.5202.Rikka with string(贪心)
Rikka with string Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- HDU 6086 Rikka with String
Rikka with String http://acm.hdu.edu.cn/showproblem.php?pid=6086 题意: 求一个长度为2L的,包含所给定的n的串,并且满足非对称. 分析 ...
- 2017 多校5 Rikka with String
2017 多校5 Rikka with String(ac自动机+dp) 题意: Yuta has \(n\) \(01\) strings \(s_i\), and he wants to know ...
- 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 ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
- ACM学习历程——HDU5202 Rikka with string(dfs,回文字符串)
Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...
- hdoj - 5202 Rikka with string (BestCoder Round #37 ($))
http://acm.hdu.edu.cn/showproblem.php?pid=5202 字符串处理的题,要细心. 给定一个只包含小写字母和问号的字符串,让我们还原出本来的字符串,把问号替换成任意 ...
随机推荐
- Loadrunder场景设计篇——手工场景设计
概述 通过选择需要运行的脚本,分配运行脚本的负载生成器,在脚本中分配Vuser来建立手工场景 手工场景就是自行设置虚拟用户的变化,主要是通过设计用户的添加和减少过程,来模拟真实的用户请求模型,完成负载 ...
- webbrowser控件——Windows下的开发利器
首先说明,本人比较菜,做C++没多长时间. 刚开始用MFC写程序时,连个基本的字体都不会变(颜色.大小等), 索性干脆就啥也不改了,直接默认,界面就那样了,老子不管了. 心想这C++做个界面咋就那么麻 ...
- Springboot文件下载
https://blog.csdn.net/stubbornness1219/article/details/72356632 Springboot对资源的描述提供了相应的接口,其主要实现类有Clas ...
- 给二维码(图片)添加文字(水印),让生成的二维码中间带logo
<?php //生成二维码 require_once IA_ROOT . '/framework/library/qrcode/phpqrcode.php'; QRcode::png($url, ...
- @MarkFan 口语练习录音 20140518 [超凡蜘蛛侠2-格温的演讲[中文]&驯龙骑士选节口语录音]
一个人看不到未来,就把握不了现在 生命中最值得珍惜的,其实并不是永恒的 正因为它会结束,使其变得弥足珍贵,而且将一去不复返 让我们谨记时间就是运气,所以不要把它浪费在别的生活上 让你的生活过得更有价值 ...
- iOS_多线程(一)
在学习多线程之前首先搞清楚以下几个问题. 并发:在同一时刻,只有一条指令被执行,多条指令进行快速切换执行. 并行:在同一时刻,多个处理器可以处理多条指令 1.什么是进程? 一个运行的程序就是 ...
- DESeq2 install --- 如何安装R包("RcppArmadillo")?
安装R包("RcppArmadillo")失败,导致依赖该包的DESeq2 无法使用: 首先对gcc,g++升级至4.7, 但依然报错,还是安装不了RcppArmadillo: 报 ...
- mybatis 中if标签判断boolean 的写法。
mybatis 的if 比较标签在比较数值时可以这样写: <if test="value=0"> </if> 在比较字符串时可以这么写: <if te ...
- Vue 什么是组件
Vue.js组件 组件的作用:组件是自定义元素,可扩展html元素,封装可复用的代码. 组件的注册一定要在初始化根实例之前,负责组件是不起作用的. 全局组件在初始化实例的时候被使用 局部组件仅在实例/ ...
- Java中各种集合特点总结
1:集合: (1) Collection(单列集合) List(有序,可重复) ArrayList 底层数据结构是数组,查 ...