题意是求一个字符串每个长度的子串出现次数最多的那个出现了多少次,也就是求每个到根的最长路的right集合最大值 。

先建后缀自动机,然后将每个前缀所在的集合的初值设为1,因为所有前缀的right集合肯定不相同,而且它们包含了所有位置。

接下来按到根的最长距离从大到小排序,将right集合累加到parent上。这么排序是因为到根的最长距离长的状态肯定不是到根的最长距离短的状态的parent。

最后直接求到根的不同的最长距离的最大的right集合就行。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define maxn 250010
using namespace std;
int ans,len,p;
int read()
{
int f=,x=;char ch=getchar();
while(isdigit(ch)== && ch!='-')ch=getchar();
if(ch=='-')f=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();
return x*f;
}
void write(int x)
{
int ff=;char ch[];
while(x)ch[++ff]=(x%)+'',x/=;
if(ff==)putchar('');
while(ff)putchar(ch[ff--]);
putchar('\n');
}
typedef struct node
{
int to[],dis,fa;
}spot;
//求每个dis的right集合最大值
//不是每个状态的right集合!!
//ass♂we♂can♂
struct SAM
{
spot x[maxn<<];
int ls,ls2,q,cnt,rt,lst,c[maxn<<],ord[maxn<<],ans[maxn<<],maxl[maxn<<];
int right[maxn<<],f[maxn<<];
char s[maxn];
inline void start()
{
lst=rt=++cnt;
scanf("%s",s+);
ls=strlen(s+);
for(int i=;i<=ls;i++)
extend(i);
}
inline void extend(int pos)
{
int val=s[pos]-'a',p=lst,np=++cnt;
lst=np,x[np].dis=pos;
for(;p&&x[p].to[val]==;p=x[p].fa)x[p].to[val]=np;
if(p==)x[np].fa=rt;
else
{
int q=x[p].to[val];
if(x[q].dis==x[p].dis+)x[np].fa=q;
else
{
int nq=++cnt;
x[nq].dis=x[p].dis+;
memcpy(x[nq].to,x[q].to,sizeof(x[q].to));
x[nq].fa=x[q].fa,x[np].fa=x[q].fa=nq;
for(;x[p].to[val]==q;p=x[p].fa)x[p].to[val]=nq;
}
}
}
inline void qsort()
{
for(int i=;i<=cnt;i++)
c[x[i].dis]++;
for(int i=;i<=ls;i++)
c[i]+=c[i-];
for(int i=;i<=cnt;i++)
ord[c[x[i].dis]--]=i;
}
inline void work()
{
for(int i=,p=rt;i<=ls;i++)
p=x[p].to[s[i]-'a'],right[p]=;
for(int i=cnt;i>=;i--){int u=ord[i];right[x[u].fa]+=right[u];}
for(int i=;i<=cnt;i++)f[x[i].dis]=max(f[x[i].dis],right[i]);
for(int i=ls;i>=;i--)f[i]=max(f[i],f[i+]);
for(int i=;i<=ls;i++)write(f[i]);
// cout<<"He doesn't have hands->"<<endl;
}
}t;
int main()
{
t.start();
t.qsort();
t.work();
return ;
}

并不对劲的SAM

听某位大佬说后缀自动机能解决所有不是字符串dp的字符串题。

并不对劲的spoj nsubstr的更多相关文章

  1. SPOJ - NSUBSTR 后缀自动机板子

    SPOJ - NSUBSTR #include<bits/stdc++.h> #define LL long long #define fi first #define se second ...

  2. SPOJ NSUBSTR (后缀自动机)

    SPOJ NSUBSTR Problem : 给一个长度为n的字符串,要求分别输出长度为1~n的子串的最多出现次数. Solution :首先对字符串建立后缀自动机,在根据fail指针建立出后缀树,对 ...

  3. 【spoj NSUBSTR】 Substrings

    http://www.spoj.com/problems/NSUBSTR/ (题目链接) 题意 给出一个字符串S,令${F(x)}$表示S的所有长度为x的子串出现次数的最大值.求${F(1)..... ...

  4. SPOJ NSUBSTR Substrings 后缀自动机

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

  5. SPOJ NSUBSTR

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

  6. SPOJ NSUBSTR Substrings

    题意 dt { font-weight: bold; margin-top: 20px; padding-left: 35px; } dd { box-shadow: 3px 3px 6px #888 ...

  7. SPOJ - NSUBSTR(长度为1-len的字串出现的最大次数

    题意:给你一个字符串,要你输出1-len的字串出现的最大次数. /** @xigua */ #include <stdio.h> #include <cmath> #inclu ...

  8. 【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

    题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为l ...

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

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

随机推荐

  1. IDEA基本使用及配置(2)

    IDEA配置:File >> Setiings进入配置界面 1.主题配置:默认两种主题,黑色.白色,可以自己在网上下载,然后File >> Import Setiings导入, ...

  2. 【转载】分布式系列文章——Paxos算法原理与推导

    转载:http://linbingdong.com/2017/04/17/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E5%88%97%E6%96%87%E7%AB%A0 ...

  3. Django-rest_framework中利用jwt登录验证时,自定义返回凭证和登录校验支持手机号

    安装 pip install djangorestframework-jwt 在Django.settings中配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATIO ...

  4. IDEA常用插件记录

    让我们来记录一下常用的IDEA插件:(从其他博客中取了许多图片,出处见图片水印) 1.JRebel for IntelliJ 热部署神器2.Free MyBatis plugin 实现dao层方法与x ...

  5. winfrom Panel 问题

    Panel 图片自适应 BackgroundImageLayout 设置成Zoom就行 Panel动态换图片时候的闪烁问题: 首先创建一个自己的panel类: using System; using ...

  6. nyoj 86 找球号(一)(set,map)

    找球号(一) 时间限制:3000 ms  |            内存限制:65535 KB 难度:3   描述 在某一国度里流行着一种游戏.游戏规则为:在一堆球中,每个球上都有一个整数编号i(0& ...

  7. ***每天一个linux命令(5):rm 删除命令

    昨天学习了创建文件和目录的命令mkdir ,今天学习一下linux中删除文件和目录的命令: rm命令.rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所 ...

  8. 洛谷——P1036 选数

    题目描述 已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n).从 n 个整数中任选 k 个整数相加,可分别得到一系列的和.例如当 n=4,k=3,4 个整数分别为 3,7,12, ...

  9. hdu4701 Game(递推博弈)

    题意: Alice初始有A元,Bob有B元. 有N个物品,第i个物品价值为Ci.Alice和Bob轮流买一些(>=1)物品.不能移动的人输.购买有一个限制,对于第1 个之后物品,只有当第i-1个 ...

  10. 奥多朗WIFI 插座

    https://aoduolang.tmall.com/category-1089563810.htm?spm=a1z10.1-b.w11212542-12917613245.12.tTWFSc&am ...