题目

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

好像前后调了两天了

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

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

首先就是跨过这个特殊字符的字符串出现次数显然都是\(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. 使用YUM安装MySQL 5.5(适用于CentOS6.2/5.8及Fedora 17/16平台)

    目前CentOS/Red Hat (RHEL) 6.2官方自带的mysql版本为5.1,mysql5.5已经出来了. 相比mysql5.1,mysql5.5不仅在多个方面进行了改进: 性能上有了很大提 ...

  2. java 配置在.properties文件中的常量

    不让用常量类,那就用.properties文件配置,放在根目录. import java.util.HashMap; import java.util.Iterator; import java.ut ...

  3. 企业为什么需要实施BPM?

    背景:众所周知,近几年企业信息化发展迅速,业务管理系统从大到小,数量众多,如ERP,SCM,PLM,CRM,EHR,OA,BI…… 等,企业的管理人员进行管理的主要手段是通过各个业务系统获得各种管理报 ...

  4. 2017年11月27日 C#MDI窗体创建&记事本打印&记事本查找、自动换行

    MDI窗体第一个父窗体 把属性里的IsMdiContainer设置为true就可以了 父窗体连接子窗体 //创建一个新的类,用来连接别的窗体,并且别的窗体为唯一窗体 List<Form> ...

  5. spring 代理

    java动态代理实现 1. Java自带的动态代理,反射生成字节码 2. Cglib调用asm生成子类 spring 中代理实现 1. 如果类实现了接口,使用java动态代理 2. 没有实现接口,使用 ...

  6. Redis学习笔记(一) ---- Linux系统中部署Redis存储系统

    Redis 一.Redis简介 1.Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合 ...

  7. hihoCoder 1148 2月29日

    时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: ...

  8. 如何对MySQL数据库中的数据进行实时同步

  9. GreenDao 初体验

    GreenDao 使用 环境搭建(android studio) project的build.gradle buildscript { repositories { google() jcenter( ...

  10. 17.分支的合并&遇到冲突时的分支合并

    分支的合并 假设你已经修正了 #53 问题,并且打算将你的工作合并入 master 分支. 为此,你需要合并 iss53 分支到 master 分支,这和之前你合并 hotfix 分支所做的工作差不多 ...