题目大意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值。F(1)..F(Length(S))

建出SAM, 然后求出Right, 求Right可以按拓扑序dp..Right就是某个点到结束状态的路径数, parent树上last的那一条链都是结束状态...然后用Right去更新答案..

spoj卡常数..一开始用DFS就炸了, 改用BFS就A了..

(贴一下丽洁姐的题解: 我们构造S的SAM,那么对于一个节点s,它的长度范围是[Min(s),Max(s)],同时他的出现次数是|Right(s)|。那么我们用|Right(s)|去更新F(Max(s))的值。同时最后从大到小依次用F(i)去更新F(i-1)即可。)

-----------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
 
using namespace std;
 
const int cn = 26;
const int maxn = 1000009;
 
bool vis[maxn];
int Right[maxn], ans[maxn], deg[maxn], n = 0, N;
char s[maxn];
 
struct Node {
Node *ch[cn], *fa;
int len, id;
} pool[maxn], *pt, *root, *last;
 
Node* newNode(int v) {
memset(pt->ch, 0, sizeof pt->ch);
pt->fa = 0;
pt->len = v;
pt->id = n++;
return pt++;
}
 
void SAM_init() {
pt = pool;
root = last = newNode(0);
}
 
void Extend(int c) {
Node *p = last, *np = newNode(p->len + 1);
for(; p && !p->ch[c]; p = p->fa)
p->ch[c] = np;
if(!p)
np->fa = root;
else {
Node* q = p->ch[c];
if(p->len + 1 == q->len)
np->fa = q;
else {
Node* nq = newNode(p->len + 1);
memcpy(nq->ch, q->ch, sizeof q->ch);
nq->fa = q->fa;
q->fa = np->fa = nq;
for(; p && p->ch[c] == q; p = p->fa)
p->ch[c] = nq;
}
}
last = np;
}
 
struct edge {
int to;
edge* next;
} E[maxn], *Pt = E, *head[maxn];
 
void AddEdge(int u, int v) {
deg[Pt->to = v]++; Pt->next = head[u]; head[u] = Pt++;
}
 
void SAM_build() {
scanf("%s", s);
N = strlen(s);
for(int i = 0; i < N; i++)
Extend(s[i] - 'a');
}
 
queue<Node*> q;
queue<int> Q;
 
void ADDEDGE() {
memset(deg, 0, sizeof deg);
memset(vis, 0, sizeof vis);
q.push(root);
vis[root->id] = true;
while(!q.empty()) {
Node* t = q.front(); q.pop();
for(int i = 0; i < cn; i++) if(t->ch[i]) {
AddEdge(t->ch[i]->id, t->id);
if(!vis[t->ch[i]->id]) {
q.push(t->ch[i]);
vis[t->ch[i]->id] = true;
}
}
}
}
 
void getRight() {
memset(Right, 0, sizeof Right);
for(Node* t = last; t; t = t->fa)
Right[t->id] = 1;
Q.push(last->id);
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(edge* e = head[x]; e; e = e->next) {
Right[e->to] += Right[x];
if(!--deg[e->to])
Q.push(e->to);
}
}
}
 
void update() {
memset(vis, 0, sizeof vis);
q.push(root);
vis[root->id] = true;
while(!q.empty()) {
Node* t = q.front(); q.pop();
ans[t->len] = max(ans[t->len], Right[t->id]);
for(int i = 0; i < cn; i++) if(t->ch[i] && !vis[t->ch[i]->id]) {
q.push(t->ch[i]);
vis[t->ch[i]->id] = true;
}
}
}
 
void solve() {
getRight();
update();
for(int i = N; --i; )
ans[i] = max(ans[i], ans[i + 1]);
for(int i = 1; i <= N; i++)
printf("%d\n", ans[i]);
}
 
int main() {
SAM_init();
SAM_build();
ADDEDGE();
solve();
return 0;
}

-----------------------------------------------------------------------------

SPOJ8222 Substrings( 后缀自动机 + dp )的更多相关文章

  1. SP8222 NSUBSTR - Substrings(后缀自动机+dp)

    传送门 解题思路 首先建出\(sam\),然后把\(siz\)集合通过拓扑排序算出来.对于每个点只更新它的\(maxlen\),然后再从大到小\(dp\)一次就行了.因为\(f[maxlen-1]&g ...

  2. 【bzoj3998】[TJOI2015]弦论 后缀自动机+dp

    题目描述 对于一个给定长度为N的字符串,求它的第K小子串是什么. 输入 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个.T=1则表示不同位置 ...

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

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

  4. Substrings(SPOJ8222) (sam(后缀自动机))

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

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

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

  6. SPOJ NSUBSTR Substrings 后缀自动机

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

  7. bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 583  Solved: 330[Submit][Statu ...

  8. fjwc2019 D1T2 原样输出(后缀自动机+dp)

    #179. 「2019冬令营提高组」原样输出 暴力对每个串建后缀自动机,然后暴力枚举每个自动机的子串.可以拿到部分分. 然鹅我们可以把每个后缀自动机连起来. 我们知道,后缀自动机是用最少的点(空间)表 ...

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

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

随机推荐

  1. IIS启动网站

    在启动一个网站前要先打开一个服务.可是Windows 的提示非常的奇怪: “除非 Windows Activation Service (WAS)和万维网发布服务(W3SVC)均处于运行状态,否则无法 ...

  2. Oracle 游标Cursor 的基本用法

    查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的 返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中.SELECT ...

  3. 删除windows7保留分区

    在系统里以管理员运行CMD.exe键入diskpartsel disk 0  (select 选择硬盘)list vol  (查看卷)sel vol 0  (选择卷,0为保留分区)inactive ( ...

  4. 注册表与盘符(转victor888文章 )

    转自: http://blog.csdn.net/loulou_ff/article/details/3769479     写点东西,把这阶段的研究内容记录下来,同时也给研究相关内容的同志提供参考, ...

  5. Delphi 重启应用程序(创建Bat文件的Process)

    Delphi 重启应用程序在工程主文件中加入Delay(500); //启动程序时请延时一段时间,否则只能重启一次 procedure RestartApp; var BatchFile: TextF ...

  6. 狼追兔子问题C模拟解

    说,一只兔子在O点处,它的洞穴在正北20m的B点处,一只狼位于兔子正东33米的A点处,模拟如下追逐问题:狼以一倍于兔子的速度紧盯兔子追击,问兔子到达洞口前是否会被狼逮住? 网上很多人说能被追上,包括类 ...

  7. 学习pthreads,给线程传递多个參数

    上篇博文中.boss线程给其它线程传递的仅仅有一个參数,那么假如是多个參数呢?怎么传递呢?也许你会有这种疑问,带着这个疑问,我们进入本文的世界,这里传递多个參数,採用结构体,为什么呢?由于结构体里能够 ...

  8. 1.4. chromium源代码分析 - chromiumframe - 消息系列

    Message framework 是对消息循环的封装和扩展,Chromium在消息循环中增加处理内部任务的工作.将内部工作处理寄生在Windows的消息循环中,会有一个问题,就是没有Windows自 ...

  9. WinSock网络编程基础(2)客户端

    接下来说一下如何用WinSock创建基于TCP/IP模型的客户端和服务器. TCP可以提供两个计算机间可靠无误的数据传输,应用程序使用TCP通信时,会在两台计算机之间建立一个虚拟连接,连接之后计算机之 ...

  10. 马踏棋盘问题-贪心(MATLAB&C++)

    原创文章,转载请注明:马踏棋盘问题-贪心(MATLAB&C++) By Lucio.Yang 1.问题描述 将马随机放在国际象棋的Board[0-7][0-7]的某个方格中,马按走棋规则进行移 ...