2019HNCPC C Distinct Substrings 后缀自动机
题意
给定一个长度为n字符串,字符集大小为m(1<=n,m<=1e6),求\(\bigoplus_{c = 1}^{m}\left(h(c) \cdot 3^c \bmod (10^9+7)\right)\)的值。其中h(c)为将c加到字符串末尾产生的新的本质不同的子串数目。
解题思路
比赛的时候没做出来,颁奖的时候听lts和lsx讲了之后发现可以用SAM做,而且板子稍微改改就可以了。
具体就是每次添加一个字符最多新建2个节点,根据SAM的性质,添加c后新建节点对本质不同的子串的数目的贡献就是h(c),用len[i]-len[link[i]]就能算出来。
现场赛的时候我一直没想到添加结点之后要怎么把这个结点再删掉,没有立刻想出来,然后就去做D数位DP了,但是其实很简单,可以把extend函数改一改,对于询问只算答案不修改原来的节点,这样就不需要删除;或者用一个容器记录修改了哪一些结点,询问完了再遍历一遍改回去。这两种方法应该都是\(O(1)\)修改的。
代码实现
和叉姐的标程对拍没有出错,应该是对的吧
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const int mod=1e9+7;
struct Suffix_Automaton{
struct state{
int len,link;
map<int,int>next;
}st[maxn<<1];
int last,tot;
int sz;
void init(){
st[1].len=0;st[0].link=0;
st[1].next.clear();
last=tot=1;;
}
int newnode(){
++tot;
st[tot].len=st[tot].link=0;
st[tot].next.clear();
return tot;
}
void extend(int c){
int p=last;
int cur=newnode();
st[cur].len=st[last].len+1;
last=cur;
while(p && !st[p].next.count(c)){
st[p].next[c]=cur;
p=st[p].link;
}
if(!p)st[cur].link=1;
else{
int q=st[p].next[c];
if(st[p].len+1==st[q].len)st[cur].link=q;
else{
int clone=newnode();
st[clone].len=st[p].len+1;
st[clone].next=st[q].next;
st[clone].link=st[q].link;
st[q].link=st[cur].link=clone;
while(st[p].next[c]==q){
st[p].next[c]=clone;
p=st[p].link;
}
}
}
}
ll solve(int c){
ll res=0;
int p=last;
int cur=newnode();
st[cur].len=st[last].len+1;
//last=cur;
while(p && !st[p].next.count(c)){
//st[p].next[c]=cur;
p=st[p].link;
}
if(!p){
st[cur].link=1;
res=st[cur].len-st[st[cur].link].len;
}
else{
int q=st[p].next[c];
if(st[p].len+1==st[q].len){
st[cur].link=q;
res=st[cur].len-st[st[cur].link].len;
}
else{
int clone=newnode();
st[clone].len=st[p].len+1;
//st[clone].next=st[q].next;
st[clone].link=st[q].link;
//while(p && st[p].next[c]==q){
//st[p].next[c]=clone;
//p=st[p].link;
//}
//st[q].link=clone;
st[cur].link=clone;
//结点q的link变为clone,所以需要把原来的删掉再把新的加进去
res=((res-(st[q].len-st[st[q].link].len))%mod+mod)%mod;
res=(res+st[q].len-st[clone].len)%mod;
res=(res+st[cur].len-st[st[cur].link].len)%mod;
res=(res+st[clone].len-st[st[clone].link].len)%mod;
}
}
tot=sz;
return (res%mod+mod)%mod;
}
}S;
int n,m;
int main()
{
while(~scanf("%d %d",&n,&m)){
S.init();
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
S.extend(x);
}
S.sz=S.tot;
ll ans=0,three=1,hc;
for(int i=1;i<=m;i++){
three=three*3%mod;
hc=S.solve(i);
ans^=(hc*three%mod);
}
printf("%lld\n",ans);
}
return 0;
}
2019HNCPC C Distinct Substrings 后缀自动机的更多相关文章
- 【CF316G3】Good Substrings 后缀自动机
[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中, ...
- SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数
题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...
- SPOJ - DISUBSTR Distinct Substrings (后缀数组)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- 【SPOJ – SUBST1】New Distinct Substrings 后缀数组
New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...
- SPOJ NSUBSTR Substrings 后缀自动机
人生第一道后缀自动机,总是值得纪念的嘛.. 后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边.许多铺垫的 ...
- ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)
题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 R ...
- SPOJ8222 NSUBSTR - Substrings(后缀自动机)
You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...
- SPOJ NSUBSTR Substrings ——后缀自动机
建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...
- SPOJ DISUBSTR Distinct Substrings 后缀数组
题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...
随机推荐
- Go:内存管理与内存清理
Illustration created for "A Journey With Go", made from the original Go Gopher, created by ...
- “随手记”开发记录day10
今天完成了各个demo合并,并进行测试,中间出现了一些bug, 例如再点击主页面预留的菜单按钮时会出现闪退 在手机上运行更新页面时会直接崩溃 还有发现的问题有,不能查看往期的记录
- 入门python有什么好的书籍推荐?纯干货推荐,你值得一看 python基础,爬虫,数据分析
Python入门书籍不用看太多,看一本就够.重要的是你要学习Python的哪个方向,或者说你对什么方向感兴趣,因为Python这门语言的应用领域比较广泛,比如说可以用来做数据分析.机器学习,也可以用来 ...
- (转载+新增)Win7下安装配置gVim
转载自 http://www.cnblogs.com/zhcncn/p/4151701.html.而后安装过程中加入自己遇到的问题解决方案. 本文根据vim官网的<Simple Steps to ...
- 解决Xshell 工具连接不上VirtualBox虚拟机
初次尝试用VirtualBox安装Linux虚拟机,却遇到了一些问题,特地记录于此,方便后面查阅! 首先简易记录下安装Linux虚拟机过程: 大致经过如下步骤:新建虚拟电脑,加载Linux版本镜像安装 ...
- 使用免费证书安装 ipa 到真机
使用免费证书安装 ipa 密码设置 进入 AppleId 官网 登录个人账号 登录进去之后, 找到 Security, 点击 Generate Password... 锁边输入几个字符, 再点击 Cr ...
- 排查Mysql突然变慢的一次过程
排查Mysql突然变慢的一次过程 上周客户说系统突然变得很慢,而且时不时的蹦出一个 404 和 500,弄得真的是很没面子,而恰巧出问题的时候正在深圳出差,所以一直没有时间 看问题,一直到今天,才算是 ...
- vue中methods互相调用的方法
a:function(goods) { this.aa= []; this.bb= 0; this.cc= 0; }, b:function(){ if(this.bbb!= 0){ this.aa= ...
- .net Core使用sql语句实现批量修改数据状态
上图为查出的所有满足条件的数据,要选中若干条数据将其状态设置为作废 一共选中6条数据,当点击确认后修改数据状态. 前端代码 1.安装NuGet包 [Abp.Dapper]于EFCore中, 2.创建文 ...
- 配置 Eureka Server 集群
简介 为了使 Eureka Server 实现高可用,我们需要为它配置集群.这样当有一台 Eureka Server 有故障时,集群中的其他 Server 可以进行代替.Eureka 集群之中的 No ...