题目

哈哈哈哈哈哈哈哈哈哈我还没自闭

好像前后调了两天了

哈哈哈哈哈哈哈哈哈哈我还没自闭

这道题就是给定一个小写字母串,回答分别把每个位置上的字符替换为\(#\)后的本质不同的子串数

首先就是跨过这个特殊字符的字符串出现次数显然都是\(1\),这部分的贡献就直接是\(i\times(n-i+1)\)

之后我们用\(SAM\)搞出所有前缀和所有后缀的本质不同子串个数,这时候答案的贡献就是\(pre_{i-1}+beh_{i+1}\)

显然会算多一些在前缀和后缀里都出现的子串

想个办法把这些东西搞出来

我们维护出每个等价类\(endpos\)的最大值\(mx[i]\)和最小值\(mi[i]\)

显然如果特殊字符插入在\([mi[i],mx[i]-len[i]]\)里的话会使得这个字符串在左右两边都被算过

如果特殊字符插入在\([mx[i]-len[i]+1,mx-len[fa[i]]\),发现这里好像需要一个每往后移动一个位置就会少多算一个子串,那就是一个公差为\(-1\)的等差数列啊,二阶差分维护一下就好了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn 600005
char S[maxn>>1];
struct SAM{
int len[maxn],fa[maxn],son[maxn][26];
LL tot;int lst,cnt;
inline void ins(int c) {
int p=++cnt,f=lst;lst=p;
len[p]=len[f]+1;
while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
if(!f) {fa[p]=1;tot+=len[p]-len[fa[p]];return;}int x=son[f][c];
if(len[f]+1==len[x]) {fa[p]=x;tot+=len[p]-len[fa[p]];return;}
int y=++cnt;tot-=len[x]-len[fa[x]];
len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
tot+=len[y]-len[fa[y]],tot+=len[p]-len[fa[p]],tot+=len[x]-len[fa[x]];
for(re int i=0;i<26;i++) son[y][i]=son[x][i];
while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
}S1,S2;
int n;
LL pre[maxn],beh[maxn];
int len[maxn],fa[maxn],son[maxn][26],mx[maxn],mi[maxn];
int lst=1,cnt=1;
int tax[maxn>>1],a[maxn];
LL c[maxn],t[maxn];
inline void extend(int c,int o) {
int p=++cnt,f=lst;lst=p;
len[p]=len[f]+1,mx[p]=mi[p]=o;
while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
if(!f) {fa[p]=1;return;}
int x=son[f][c];
if(len[f]+1==len[x]) {fa[p]=x;return;}
int y=++cnt;len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
for(re int i=0;i<26;i++) son[y][i]=son[x][i];
while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int main() {
scanf("%d",&n);scanf("%s",S+1);S1.lst=S1.cnt=1;S2.lst=S2.cnt=1;
for(re int i=1;i<=n;i++) S1.ins(S[i]-'a'),pre[i]=S1.tot;
for(re int i=n;i;i--) S2.ins(S[i]-'a'),beh[i]=S2.tot;
memset(mi,20,sizeof(mi));
for(re int i=1;i<=n;i++) extend(S[i]-'a',i);
for(re int i=1;i<=cnt;i++) tax[len[i]]++;
for(re int i=1;i<=n;i++) tax[i]+=tax[i-1];
for(re int i=cnt;i;--i) a[tax[len[i]]--]=i;
for(re int i=cnt;i;--i) {
int x=a[i];
mx[fa[x]]=max(mx[fa[x]],mx[x]);mi[fa[x]]=min(mi[fa[x]],mi[x]);
}
for(re int i=2;i<=cnt;i++) {
if(mi[i]==mx[i]) continue;
int L=mx[i]-len[i]+1,R=mx[i]-len[fa[i]]-1;
if(L<=mi[i]+1) {
L=mi[i]+1;int li=R-L+1;
if(L>R) continue;
t[L]+=li;
t[L+1]+=-1-li;
t[R+2]+=1;
continue;
}
c[mi[i]+1]+=len[i]-len[fa[i]];c[L]-=len[i]-len[fa[i]];
if(len[i]-len[fa[i]]>1) {
if(L>R) continue;
t[L]+=len[i]-len[fa[i]]-1;
t[L+1]+=-len[i]+len[fa[i]];
t[R+2]+=1;
}
}
for(re int i=1;i<=n;i++) t[i]+=t[i-1];
for(re int i=1;i<=n;i++) c[i]+=c[i-1]+t[i];
for(re int i=1;i<=n;i++)
printf("%lld ",pre[i-1]+beh[i+1]-c[i]+(LL)i*(LL)(n-i+1));
puts("");
return 0;
}

「hihocoder1413 Rikka with String」的更多相关文章

  1. [HihoCoder1413]Rikka with String

    vjudge 题意 给你一个串,问你把每个位置的字符替换成#后串中有多少本质不同的子串. \(n\le 3*10^5\) sol 首先可以计算出原串里面有多少本质不同的子串.显然就是\(\sum_{i ...

  2. 【Hihocoder1413】Rikka with String(后缀自动机)

    [Hihocoder1413]Rikka with String(后缀自动机) 题面 Hihocoder 给定一个小写字母串,回答分别把每个位置上的字符替换为'#'后的本质不同的子串数. 题解 首先横 ...

  3. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  4. 「kuangbin带你飞」专题十八 后缀数组

    layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...

  5. 「kuangbin带你飞」专题十七 AC自动机

    layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...

  6. 「kuangbin带你飞」专题十二 基础DP

    layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathj ...

  7. 「持续集成实践系列 」Jenkins 2.x 构建CI自动化流水线常见技巧

    在上一篇文章中,我们介绍了Jenkins 2.x实现流水线的两种语法,以及在实际工作中该如何选择脚本式语法或声明式语法.原文可查阅:「持续集成实践系列」Jenkins 2.x 搭建CI需要掌握的硬核要 ...

  8. Socket的用法——NIO包下SocketChannel的用法 ———————————————— 版权声明:本文为CSDN博主「茶_小哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ycgslh/article/details/79604074

    服务端代码实现如下,其中包括一个静态内部类Handler来作为处理器,处理不同的操作.注意在遍历选择键集合时,没处理完一个操作,要将该请求在集合中移除./*模拟服务端-nio-Socket实现*/pu ...

  9. 「THP3考前信心赛」解题报告

    目录 写在前面&总结: T1 T2 T3 T4 写在前面&总结: \(LuckyBlock\) 良心出题人!暴力分给了 \(120pts\) \(T1\) 貌似是个结论题,最后知道怎么 ...

随机推荐

  1. Golang教程:函数、变参函数

    函数是完成一个特定任务的代码块.一个函数接受输入,对输入进行一些运算并产生输出. 函数声明 在 Go 中声明一个函数的语法为: func functionname(parametername type ...

  2. 定时器setTimeout()和setInterval()使用心得整理

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成. 一.setTimeout() setTimeout函 ...

  3. [javaSE] java上传图片给PHP

    java通过http协议上传图片给php文件,对安卓上传图片给php接口的理解 java文件: import java.io.DataOutputStream; import java.io.File ...

  4. gradle -v不是外部命令, 内部命令,或批处理文件

    安装完gradle并且配置了环境变量之后,使用windos+R,cmd 进入Dos命令gradle -v检测版本号出现了: 1 --首先找到gradle文件所在目录 一般是在C:\Users\su\. ...

  5. centos自带python2.6升级到python2.7。并解决yum pip easy_install pip等模块兼容性问题

    参考原文:  https://www.cnblogs.com/kimyeee/p/7250560.html   https://www.cnblogs.com/galaxy-gao/p/5796488 ...

  6. Spring课程 Spring入门篇 6-1 Spring AOP API的PointCut、advice的概念及应用

    本节主要是模拟spring aop 的过程. 实现spring aop的过程 这一节老师虽然说是以后在工作中不常用这些api,实际上了解还是有好处的, 我们可以从中模拟一下spring aop的过程. ...

  7. lincode 题目记录5

    Course Schedule 安排课表   Frog Jump  最长回文字符串长度 Course Schedule 选课方案问题,题目说的很清楚了就是bfs或者dfs,然后加个字典优化,弄了好久没 ...

  8. is not mapped 错误改正

    我出现的错误是:oorg.hibernate.hql.ast.QuerySyntaxException: DEPT is not mapped [from DEPT] 配置文件如下: <?xml ...

  9. JS原型学习笔记

    1.原型是函数对象的属性,它的初始值是一个空对象,这个prototype原型对象可以添加方法和属性. 2.构造器对象查找属性和方法时先查找构造器后查找原型. 3.若构造器中的属性和原型中的属性相同,构 ...

  10. Sencha Architect打开闪退问题修复

    删除以下位置的cache文件夹 C:\Users\Administrator\AppData\Local\Sencha\Sencha Architect 3.2\Cache bug解决参考 https ...