题意

给定一个长度为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 后缀自动机的更多相关文章

  1. 【CF316G3】Good Substrings 后缀自动机

    [CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中, ...

  2. SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数

    题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...

  3. SPOJ - DISUBSTR Distinct Substrings (后缀数组)

    Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...

  4. 【SPOJ – SUBST1】New Distinct Substrings 后缀数组

    New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...

  5. SPOJ NSUBSTR Substrings 后缀自动机

    人生第一道后缀自动机,总是值得纪念的嘛.. 后缀自动机学了很久很久,先是看CJL的论文,看懂了很多概念,关于right集,关于pre,关于自动机的术语,关于为什么它是线性的结点,线性的连边.许多铺垫的 ...

  6. ●SPOJ 8222 NSUBSTR–Substrings(后缀自动机)

    题链: http://www.spoj.com/problems/NSUBSTR/ 题解: 后缀自动机的水好深啊!懂不了相关证明,带着结论把这个题做了.看来这滩深水要以后再来了. 本题要用到一个叫 R ...

  7. SPOJ8222 NSUBSTR - Substrings(后缀自动机)

    You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as ...

  8. SPOJ NSUBSTR Substrings ——后缀自动机

    建后缀自动机 然后统计次数,只需要算出right集合的大小即可, 然后更新f[l[i]]和rit[i]取个max 然后根据rit集合短的一定包含长的的性质,从后往前更新一遍即可 #include &l ...

  9. SPOJ DISUBSTR Distinct Substrings 后缀数组

    题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...

随机推荐

  1. 010_go语言中的maps映射(字典)

    代码演示 package main import "fmt" func main() { m := make(map[string]int) m["k1"] = ...

  2. 7、Java 循环结构

    本章讲解一下Java中常见的三种循环结构,顺序结构的程序语句只能 被执行一次.使用循环可以解决我们多个常量或者变量的同一类的操作或者更加复杂的操作. 循环 循环结构有三大类: 1.for循环:确定循环 ...

  3. SCHP代码中的问题

    1.subprocess.CalledProcessError: Command ‘[‘where’, ‘cl’]’ returned non-zero exit status 1. 这个问题是因为电 ...

  4. 2020-04-13:怎么在日志里排查错误,该用哪些Linux命令

    能通过less命令打开文件,通过Shift+G到达文件底部,再通过?+关键字的方式来根据关键来搜索信息. 能通过grep的方式查关键字,具体用法是, grep 关键字 文件名,如果要两次在结果里查找的 ...

  5. Webpack 定义process.env的时机

    定义 process.env的时机 如果已经提取了公共配置文件 webpack.common.js 分别定义了开发配置webpack.dev.js和生产配置webpack.prod.js 在webpa ...

  6. kereas 实现鸢尾花分类

    import tensorflow as tf from sklearn import datasets import numpy as np x_train=datasets.load_iris() ...

  7. JS实例—DOM的增删改

    <!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" ...

  8. Express Response 之 end /send 傻傻分不清楚

    Express是一个轻量的经典的Node.js开启服务和快速路由管理的库.开启服务的方式也是非常的简单 只需要简单的,安装 $ npm install express   -------> 引入 ...

  9. equals&hashCode

    经典规则:如果重写了equals,必须重写hashCode 为什么??? 这个规则考虑的应用场景:如果你的对象可能放入HashMap,HashSet,不重写会出问题 问题场景: new一个对象,重写了 ...

  10. AMD 5700 XT显卡装ubuntu18.04.* 驱动的问题解决(全)

    公司开发需要测试新的 AMD显卡,由于测试服务器上的显卡是英伟达的显卡所以换完后要安装相应的驱动.由于之前装机的同事装的ubuntu是18.04.5 恰巧18.04.5在amd官网上没有相匹配的驱动( ...