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 ...
随机推荐
- three.js 着色器材质之glsl内置函数
郭先生发现在开始学习three.js着色器材质时,我们经常会无从下手,辛苦写下的着色器,也会因莫名的报错而手足无措.原因是着色器材质它涉及到另一种语言–GLSL,只有懂了这个语言,我们才能更好的写出着 ...
- Mixed Precision Training —— caffe-float16
简介 最近有了突如其来的想法,如何把caffe的变得更小更快.后来翻到Nvidia开发caffe-float16,同时也看到它的论文.看完大致了解一番后,就做一下记录. 该工作的目标是,减少网络的所需 ...
- 代码优化之return 减少括号嵌套
代码优化之return 减少括号嵌套 例如下面的公共方法 // 优化 substring方法 解决边界越界问题 空指针问题 优化前 public static String subString ...
- C#LeetCode刷题之#205-同构字符串(Isomorphic Strings)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3770 访问. 给定两个字符串 s 和 t,判断它们是否是同构的. ...
- PowerJob 的自实现高可用方案,妙妙妙!
本文适合有 Java 基础知识的人群 作者:HelloGitHub-Salieri HelloGitHub 推出的<讲解开源项目>系列. 碎碎念 高可用放到今天已经不是一个新颖的词汇了,怎 ...
- 运放引脚悬空危害大,单片机PWM信号进入运放需要考虑避免运放引脚悬空
1 问题电路 在没有烧录程序时,单片机的PWM引脚无信号,导致运放的3脚悬空,从而导致运放输出3.5V电压,从二导致后面驱动电流非常大,容易对驱动器件造成损坏 2 改进电路 通过在单片机输出增加下拉电 ...
- 多次调用Promise的then会返回什么?
//做饭 function cook(){ console.log('开始做饭.'); var p = new Promise(function(resolve, reject){ //做一些异步操作 ...
- 【NOI2015】荷马史诗 - 哈夫曼树
题目描述 追逐影子的人,自己就是影子 ——荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...
- CardView之可切换式卡片
今天我所要作的笔记是: 可切换式的卡片CardView. Java代码部分 1.我们要根据自己的当前版本号添加相对应的一个依赖: implementation 'com.android.support ...
- centos7上借助于xargs快速查询并卸载rpm软件
在centos上卸载某些软件的时候,如果查询的软件包比较多,可以考虑使用xargs,边查询边卸载 如:下面在查询mysql包时候,将查询结果通过管道传送给xargs,然后使用rpm -e --node ...