题目

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

好像前后调了两天了

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

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

首先就是跨过这个特殊字符的字符串出现次数显然都是\(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. yii1的笔记

    $sql = 'SELECT * FROM to8to_worker_item limit 10'; $res = Yii::app()->db->createCommand($sql)- ...

  2. .net托管资源与非托管资源

    在项目当中用到的资源分为托管资源和非托管资源,托管资源无非就是什么int.string.datatime之类,托管资源不需要人为去管理,.net framework中有专门针对托管资源的管理机制(GC ...

  3. 推荐几款基于Bootstrap的响应式后台管理模板

    1.Admin LTE 该模版开源免费. AdminLTE - 是一个完全响应式管理模板.基于Bootstrap3的框架.高度可定制的,易于使用.支持很多的屏幕分辨率适合从小型移动设备到大型台式机. ...

  4. js密码强度校验

    function AuthPasswd(string) { if(!string){ jQuery("#low").removeClass("org"); }) ...

  5. Browser对象之Window对象

    对象属性 对象方法 setInterval() 按照指定的周期(以毫秒计)来调用函数或计算表达式. setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式. setInte ...

  6. Java基础(三)选择和循环结构

    一.选择结构,条件判断 1.if 语句 一个 if 语句包含一个布尔表达式和一条或多条语句.如果布尔表达式的值为 true,则执行 if 语句中的代码块,否则执行 if 语句块后面的代码. impor ...

  7. Java温故而知新(10)类的加载机制

    类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性 ...

  8. null id in com.rocky.** entry 错误处理

    1. 概述 使用hibernate往mysql数据库插入记录出错如下 10:37:57,364 ERROR [AssertionFailure] an assertion failure occure ...

  9. JavaScript String对象常用方法

    length 返回字符串的长度(字符数) var str='Hello World!'; str.length; charAt() 返回指定位置的字符,第一个字符位置为0 var str='Hello ...

  10. css手风琴

    <style> .box{ width: 1000px; height: 450px; margin:0 auto; overflow: hidden;} .box div{ width: ...