题目链接:点击查看

题目大意:

蒜斜刚来PKU的时候还不知道有“北大算协”这个社团,因此他总是觉得周围的人在偷偷议论着他,比如说:

“算协(注:非蒜斜)举办的活动好有趣啊!”

“算协(注:非蒜斜)好帅啊!”

蒜斜每次听到这些话就会想入非非,但仔细想想,自己好像也没有那么帅吧?最离谱的一次还是:

“算协(注:非蒜斜)有好多小哥哥”(雾)

自从蒜斜学习了半前缀之后,他把这些话都看开了 —— 对他来说,只要这些话里有 “蒜斜好” 的半前缀就足够了。

题目描述

设小写字母字符串 s, 长度为 n, s[l:r] 表示第 l 个到第 r 个字符构成的子串, l>r 时对应空串。

定义半前缀是 s[1:i]+s[j:k], 其中 0≤i<len(s),i<j≤len(s),j−1≤k≤len(s)。直观上来说,你可以把半前缀理解成某一个前缀 s[1:k]删除掉某一个子串后形成的结果(当然也允许不删)。

给出字符串 ss,你需要求出 ss 的所有半前缀中,有多少个不同的字符串。

输入格式

输入一行包含一个小写字符串 s(1≤|s|≤106)。

输出格式

输出一行一个整数,表示答案。

样例一

input

aab

output

6

explanation

字符串 aab 的半前缀有:空串,abaaabaab

样例二

input

pkusaamtcup

output

217

限制与约定

Small Task: |s|≤3000。

Large Task: |s|≤106。

时间限制:2s

空间限制:512MB

题目分析:读完题后第一反应就是后缀自动机,但是需要猜结论或者变形,然后就止步于此了

赛后看了jls的讲题视频豁然开朗,感觉这个题目太妙了

首先因为题目规定的半前缀是一个前缀与一个子串拼接而成,对于每个半前缀而言,肯定有很多的拼接方法,如果不加以约束的话,很容易重复统计,对于每个半前缀 s[ 0 : i ] + s[ j : k ] 我们只计算 i 最大的那个半前缀这样就能做到不重不漏了

该如何确定某个半前缀已经是 i 最大的呢,一个必要条件是 s[ i + 1 ] != s[ j ] ,这个比较容易看出来,因为如果 s[ i + 1 ] == s[ j ] 的话,那么显然 s[ 0 : i + 1 ] + s[ j + 1 : k ] 是一个比 i 更靠后的半前缀,所以必要性成立

接下来证明一下充分性,假设有更靠后的一个半前缀 s[ 0 : i' ] + s[ j' : k' ] 满足 i < i' ,因为 s[ 0 : i ] + s[ j : k ] == s[ 0 : i' ] + s[ j' : k' ] ,所以 s[ i + 1 : i' ] == s[ j : j + [一段区间] ] ,即 s[ i + 1 ] == s[ j ] ,与上面的结论相悖,所以证明了充分性

综上,s[ i + 1 ] != s[ j ] 是 s[ 0 : i ] + s[ j : k ] 作为最后一次出现的半前缀的重分必要条件

那么接下来我们只需要枚举 i ,然后统计 s[ i + 1 : k ] 中有多少个首字母不为 s[ i + 1 ] 的本质不同子串即可

然后用后缀自动机解决就好了,因为要统计的区间实际上为 [ i + 1 , n ] ,所以我们可以倒着插入字符串,因为字符串在翻转之后,本质不同的子串个数是不变的,每次插入后利用 last 指针更新 cnt 数组,cnt[ j ] 表示截止到目前为止,首字母为 j 的本质不同子串有多少个,将答案累加就好了

最后需要注意的是,初始化为赋值为 n + 1 ,这里的 1 是指空串,而 n 是指形如 [ 1 , 1 ] + 空串,[ 1 , 2 ] + 空串, [ 1 , 3 ] + 空串... +  [ 1 , n ] + 空串 ,这样的半前缀,因为后缀自动机无法统计空串的个数,所以需要我们自己手动计算上空串的贡献

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;char s[N];LL cnt[26];int tot=1,last=1;struct Node
{int ch[26];int fa,len;
}st[N<<1];void add(int x)
{int p=last,np=last=++tot;st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=++tot;st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替换成nq}}
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);scanf("%s",s);int n=strlen(s);LL ans=n+1;for(int i=n-1;i>=0;i--){add(s[i]-'a');cnt[s[i]-'a']+=st[last].len-st[st[last].fa].len;for(int j=0;j<26;j++)if(s[i]-'a'!=j)ans+=cnt[j];}printf("%lld\n",ans);return 0;
}

美团杯2020 - 半前缀计数(后缀自动机)相关推荐

  1. 美团杯2020:查查查乐乐(dp)

    A. [美团杯2020]查查查乐乐 "查查查乐乐"是一段古老神秘的咒语,只有被选中的魔法师才有资格使用这一段咒语并享用它所带来的力量:而如果这段咒语出现在了不具资格的魔法师的口中, ...

  2. 【美团杯2020】字符串处理:查查查乐乐

    美团杯:签到题 我:一个小时自闭题 查查查乐乐 [题目] "查查查乐乐"是一段古老神秘的咒语,只有被选中的魔法师才有资格使用这一段咒语并享用它所带来的力量:而如果这段咒语出现在了不 ...

  3. BZOJ 4180: 字符串计数 后缀自动机 + 矩阵乘法 + 二分(神题)

    Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', ...

  4. BZOJ.4180.字符串计数(后缀自动机 二分 矩阵快速幂/倍增Floyd)

    题目链接 先考虑 假设S确定,使构造S操作次数最小的方案应是:对T建SAM,S在SAM上匹配,如果有S的转移就转移,否则操作数++,回到根节点继续匹配S.即每次操作一定是一次极大匹配. 简单证明:假设 ...

  5. 美团杯2020 - 平行四边形(原根)

    题目链接:点击查看 题目大意: 蒜斜非常喜欢下围棋.自从AlphaOg面世以来,他就立志一定要研究出AlphaOg的破绽. 终于,他发现当AlphaOg遇到一种特殊局面后,它的神经网络会自动输出&qu ...

  6. 【美团杯2020】114514 解题报告

    原题地址:http://uoj.ac/contest/53/problem/529 这题说实话我觉得有点玄学.我的方法是从左到右贪心,优先给每个4分配两个1,1不够的时候就再取出来.虽然我也意识到思路 ...

  7. 【UOJ529】【美团杯2020】114514

    题目链接 点击打开链接 题目解法 可以发现,在给定的序列 114514 114514 114514 中,每个 4 4 4 之前均有一个 1 1 1 . 因此,从后向前,将每个 4 4 4 与前方最近的 ...

  8. hihocoder 后缀自动机专题

    一.后缀自动机基本概念的理解 1.首先后缀自动机的状态是由子串的endpos来决定的 子串的endpos是指一个子串可以在原字符串的哪些位置进行匹配, endpos构成的不同集合划分成不同的状态 关于 ...

  9. BZOJ3998: [TJOI2015]弦论(后缀自动机,Parent树)

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

最新文章

  1. Oxford Nanopore sequencing, hybrid error correction, and de novo assembly of a eukaryotic genome
  2. Spring框架的灵魂IOC和AOP
  3. iOS开发之 [NSNull length]:unrecognized selector sent
  4. 全三轨磁条卡读写器|写卡器MSR606的驱动安装与Demo软件测试操作指南
  5. RC振荡电路 双三极管多谐振荡器
  6. iOS逆向及逆向防护相关资料
  7. oracle用户LOCKED(TIMED)原因及解决
  8. 电脑重装系统苹果电脑开不了机的原因分析
  9. java inflate deflate_Python:Inflate和Deflate实现
  10. 推荐一些学习类APP
  11. 带exp在线计算机计算器使用,电脑系统自带科学计算器使用方法
  12. 设计模式综合实例分析之数据库同步系统(一)
  13. ACM-ICPC Jiaozuo Onsite 2018 Resistors in Parallel (思维+java大数+找规律)
  14. mapbox加载天地图
  15. Mesalink v1.0.0 发布,正式支持 TLS 1.3 和 IPv6,支持CMake编译,支持Windows,实现生产环境可用...
  16. loss.item()大坑
  17. Lytro 一代资料.缘起
  18. 安全合规/法案--29--《网络安全法》原文及解读
  19. 2-3-2 rsync+inotify备份同步数据
  20. 校招实习面试实战,顺丰科技Java工程师面试复盘总结

热门文章

  1. html插入javascript变量,javascript如何引用变量?
  2. oracle某些服务在有其他服务,oracle 监听无法启动,出现某些服务再未由其他服务或程序使用时自动停止。...
  3. ConcurrentHashMap的源码分析-CounterCells解释
  4. MyBatis 实际使用案例-typeHandlers【重点】
  5. 对称加密-DES加密
  6. ApplicationContext应用上下文获取方式
  7. 递归-递归实现数字累加
  8. python查微信好友是否删除自己_Python + Appium 自动化操作微信查找自己是否被删除...
  9. php如何获取百度快照,PHP获取某网站的百度快照日期方法
  10. 单片机蓝牙烧录_蓝牙模块与单片机如何连接?