【spoj8222】Substrings

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #define maxn 500005
 7 #define maxm 250005
 8 using namespace std;
 9
10 int n,tot,root,last,f[maxm],fa[maxn],son[maxn][26],dist[maxn],ri[maxn],sum[maxm],tmp[maxn];
11 char st[maxm];
12 struct Tsegment{
13     void prepare(){tot=root=last=1; memset(dist,0,sizeof(dist)); memset(sum,0,sizeof(sum));}
14     int newnode(int x){
15         dist[++tot]=x; return tot;
16     }
17     void add(int x){
18         int p=last,np=newnode(dist[last]+1); last=np;
19         for (;p&&!son[p][x];p=fa[p]) son[p][x]=np;
20         if (p==0) fa[np]=root;
21         else{
22             int q=son[p][x];
23             if (dist[p]+1==dist[q]) fa[np]=q;
24             else{
25                 int nq=newnode(dist[p]+1);
26                 memcpy(son[nq],son[q],sizeof(son[q]));
27                 fa[nq]=fa[q],fa[q]=fa[np]=nq;
28                 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
29             }
30         }
31     }
32 }SAM;
33
34 int main(){
35     scanf("%s",st+1),n=strlen(st+1);
36     SAM.prepare();
37     for (int i=1;i<=n;i++) SAM.add(st[i]-‘a‘);
38     last=root;
39     for (int i=1;i<=n;i++) last=son[last][st[i]-‘a‘],ri[last]=1;
40     memset(sum,0,sizeof(sum));
41     for (int i=1;i<=tot;i++) sum[dist[i]]++;
42     for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
43     for (int i=1;i<=tot;i++) tmp[sum[dist[i]]--]=i;
44     memset(f,0,sizeof(f));
45     for (int i=tot;i>=1;i--){
46         int x=tmp[i];
47         if (fa[x]) ri[fa[x]]+=ri[x];
48     }
49     for (int i=1;i<=tot;i++) f[dist[i]]=max(f[dist[i]],ri[i]);
50     for (int i=n-1;i>=1;i--) f[i]=max(f[i],f[i+1]);
51     for (int i=1;i<=n;i++) printf("%d\n",f[i]);
52     return 0;
53 }

题目链接:http://www.spoj.com/problems/NSUBSTR/

题目大意:给定一个长度为n的字符串,n<=250000,求f[i],i属于[1,n],f[i]表示在给定字符串中长度为i的子串的最多出现次数。

做法:初看此题,我也是一脸懵逼,后来发现出现次数与后缀自动机中的right集合大小有关,这题主要就是如何求right集合的大小,即该点表示的状态的右端点的个数(即出现次数),初始时我们从root开始匹配全串,途径的节点我们设其right为1,其余的节点设为0,某个节点的right就是parent树中以它为根的子树中的right值的和,一次dp即可。注解:parent树是我们记录的fa数组所构成的树,该步骤具体细节见代码。

dist表示SAM上该节点所表示的状态所能代表的最长的字符串长度,我们用right【i】去更新f【dist【i】】即可,最后用一次类似前缀和的算法,求一次后缀最值,显然,长度越小,出现次数一定不会减少。最后输出f数组即可。

后缀自动机。

时间: 2024-10-30 21:40:09

【spoj8222】Substrings的相关文章

【spoj8222】 Substrings

http://www.spoj.com/problems/NSUBSTR/ (题目链接) 题意 给出一个字符串S,令${F(x)}$表示S的所有长度为x的子串出现次数的最大值.求${F(1)......F(length(S))}$ Solution 后缀自动机例题,下面写几点自己认为理解后缀自动机的重点. 后缀自动机相对于后缀树就是将Right集合相同的子串合用一个节点来表示.每一个节点代表一个状态S,这个状态可能包含很多长度区间连续的子串,这些子串的右端点固定,它们的Right集合相同. 往上

【SPOJ8222】Substrings (后缀自动机)

题意: 给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值. 求F(1)..F(Length(S)) Length(S) <= 250000 思路:板子中st[x]定义为root到x的最多步数,可以用来更新所有长度为[1..st[x]]的答案 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned int uint; 5 typedef u

【SPOJ】Substrings(后缀自动机)

/* 求right集合大小 然后后缀最大值 */ #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<queue> #define ll long long #define M 600010 #define mmp make_pair using namespace std; int read() { int nm = 0, f =

【CF316G3】Good Substrings 后缀自动机

[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中,有多少个满足所有限制. |S|,|p|<=10^5,n<=10. 题解:比较简单的后缀自动机题,我们先把原串和所有限制串放到一起建一个广义后缀自动机,然后在pre树上统计一下即可得到每个子串在每个限制串中出现了多少次.现在我们想知道原串中有多少满足条件的子串,即我们统计一下所有出现次数符合要求的,

【SPOJ】Distinct Substrings(后缀自动机)

[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/endpos\)集合的大小 但是实际上我们没有任何必要减去不合法的数量 我们只需要累加每个节点表示的合法子串的数量即可 这个值等于\(longest-shortest+1=longest-parent.longest\) #include<iostream> #include<cstdio&g

LeetCode | 1358. Number of Substrings Containing All Three Characters包含所有三种字符的子字符串数目【Python】

LeetCode 1358. Number of Substrings Containing All Three Characters包含所有三种字符的子字符串数目[Medium][Python][双指针][滑窗] Problem LeetCode Given a string s consisting only of characters a, b and c. Return the number of substrings containing at least one occurrence

【spoj705】 Distinct Substrings

[题目描述] 给定一个字符串,计算其不同的子串个数. [输入格式] 一行一个仅包含大写字母的字符串,长度<=50000 [输出格式] 一行一个正整数,即不同的子串个数. [样例输入] ABABA [样例输出] 9 [思路] 一看就知道是后缀数组题啦-但是我不会写QAQ..只好现学现用啦- 在字符串最后补上一个'$',不因为别的只因为它比‘A’还要小..不然你补ascII码是0的也可以.. 申请rank数组和sa数组,rank[i]=j代表后缀i排第j位,sa[i]=j代表排名第i的是后缀j.也就

【转】对于杭电OJ题目的分类

[好像博客园不能直接转载,所以我复制过来了..] 1001 整数求和 水题1002 C语言实验题——两个数比较 水题1003 1.2.3.4.5... 简单题1004 渊子赛马 排序+贪心的方法归并1005 Hero In Maze 广度搜索1006 Redraiment猜想 数论:容斥定理1007 童年生活二三事 递推题1008 University 简单hash1009 目标柏林 简单模拟题1010 Rails 模拟题(堆栈)1011 Box of Bricks 简单题1012 IMMEDI

【BZOJ2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机

[BZOJ2780][Spoj]8093 Sevenk Love Oimaster Description Oimaster and sevenk love each other.     But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman's nature, sevenk felt angry and began to check oimaster's online t