Substrings SPOJ - NSUBSTR (后缀自动机)
Substrings
\]
题意
给出一个长度为 \(250000\) 的字符串,求出所有 \(x\) 的 \(F(x)\) 。
\(F(x)\) 含义为长度为 \(x\) 的子串出现的最多次数。
思路
先对给出的串构建后缀自动机,设 \(dp[i]\) 为后缀自动机上节点 \(i\) 包含的最长子串的出现的次数。那么对于主链的上的点,可以直接赋初始值 \(dp[i] = 1\),也就是从根节点直接走到当前节点。
对于任意节点 \(i\) ,\(i\) 中出现的子串必定也会在其 \(father\) 上出现,所以我们可以得到
dp[father] += dp[i]。
如此就可以计算出节点 \(i\) 的子串的出现次数,得到
anslen[node[i].len] = max(anslen[node[i].len], dp[i]);
现在求出的是对于每个节点上 \(maxlen\) 的 \(anslen\),对于 \(\left[minlen,maxlen-1\right]\) 范围内还没有求出来,所以我们还要在更新一遍。
因为长度更短的子串一定包括在长度更长的子串中,所以可以得到
anslen[i] = max(anslen[i], anslen[i+1]);
最后输出\(anslen\)就是题目的\(F(x)\)。
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout)
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 3e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
struct SAM {
struct Node{
int next[27];
int len, fa;
void init() {
mes(next, 0);
len = fa = 0;
}
} node[maxn<<1];
vector<int> vv[maxn<<1];
int dp[maxn<<1], anslen[maxn];
int sz, last;
void init() {
sz = last = 1;
node[sz].init();
mes(dp, 0);
mes(anslen, 0);
}
void insert(int k) {
int p = last, np = last = ++sz;
node[np].init();
dp[np] = 1;
node[np].len = node[p].len+1;
for(; p&&!node[p].next[k]; p=node[p].fa)
node[p].next[k] = np;
if(p==0) {
node[np].fa = 1;
} else {
int q = node[p].next[k];
if(node[q].len == node[p].len + 1) {
node[np].fa = q;
} else {
int nq = ++sz;
node[nq] = node[q];
node[nq].len = node[p].len+1;
node[np].fa = node[q].fa = nq;
for(; p&&node[p].next[k]==q; p=node[p].fa)
node[p].next[k] = nq;
}
}
}
void dfs(int u) {
for(auto v : vv[u]) {
dfs(v);
dp[u] += dp[v];
}
anslen[node[u].len] = max(anslen[node[u].len], dp[u]);
}
void solve(int len) {
for(int i=1; i<=sz; i++) {
vv[i].clear();
}
for(int i=2; i<=sz; i++) {
vv[node[i].fa].push_back(i);
}
dfs(1);
for(int i=len-1; i>=1; i--) {
anslen[i] = max(anslen[i], anslen[i+1]);
}
for(int i=1; i<=len; i++) {
printf("%d\n", anslen[i]);
}
}
} sam;
char s[maxn];
int main() {
scanf("%s", s+1);
sam.init();
int len = strlen(s+1);
for(int i=1; i<=len; i++) {
sam.insert(s[i]-'a'+1);
}
sam.solve(len);
return 0;
}
Substrings SPOJ - NSUBSTR (后缀自动机)的更多相关文章
- SPOJ NSUBSTR (后缀自动机)
SPOJ NSUBSTR Problem : 给一个长度为n的字符串,要求分别输出长度为1~n的子串的最多出现次数. Solution :首先对字符串建立后缀自动机,在根据fail指针建立出后缀树,对 ...
- SPOJ - NSUBSTR 后缀自动机板子
SPOJ - NSUBSTR #include<bits/stdc++.h> #define LL long long #define fi first #define se second ...
- 长度为x的本质不同的串的出现次数 SPOJ - NSUBSTR 后缀自动机简单应用
题意: 长度为x的本质不同的串的出现次数 题解: 先处理出每一个节点所对应的子串出现的次数 然后取max就好了 #include <set> #include <map> #i ...
- Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))
Given a string, we need to find the total number of its distinct substrings. Input \(T-\) number of ...
- Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)
Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题 ...
- SPOJ LCS 后缀自动机
用后缀自动机求两个长串的最长公共子串,效果拔群.多样例的时候memset要去掉. 解题思路就是跟CLJ的一模一样啦. #pragma warning(disable:4996) #include< ...
- Substrings(SPOJ8222) (sam(后缀自动机))
You are given a string \(S\) which consists of 250000 lowercase latin letters at most. We define \(F ...
- SPOJ - LCS 后缀自动机入门
LCS - Longest Common Substring A string is finite sequence of characters over a non-empty finite set ...
- SPOJ LCS 后缀自动机找最大公共子串
这里用第一个字符串构建完成后缀自动机以后 不断用第二个字符串从左往右沿着后缀自动机往前走,如能找到,那么当前匹配配数加1 如果找不到,那么就不断沿着后缀树不断往前找到所能匹配到当前字符的最大长度,然后 ...
随机推荐
- JAVA并发编程: CAS和AQS
版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u010862794/article/details/72892300 说起JAVA并发编程,就不得不聊 ...
- 在C++中调用FFTW
FFTW是一个可以进行可变长度一维或多维DFT的开源C程序库,是目前最快的FFT算法实现. 本文简述了在Windows平台上,如何在C++中调用FFTW,所使用的IDE为Visual Studio 2 ...
- Prometheus 标签使用示例整合
Prometheus 监控实例 一.Prometheus 根据标签聚合总CPU使用率 1.主机添加标签(可在多个主机内添加相同标签实现聚合):vim prometheus.conf static_co ...
- 浅谈maven setting.xml 设置的mirrorof标签作用。
https://blog.csdn.net/whbing1471/article/details/53983779 A 看这一段 背景:写好的java项目放置到linux服务器上进行编辑的时候,由于m ...
- Mybatis+MySql 一个标签中执行多条sql语句
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/cxfly957/article/details/77896590 MySql默认是不支持这种骚操作的 ...
- SQL Server的外键必须引用的是主键或者唯一键(转载)
问: In SQL Server , I got this error -> "There are no primary or candidate keys in the refere ...
- js 时间格式化成字符串
我用的简单的直接的字符串格式转化 function getTimeStr() { var date = new Date(); var year = date.getFullYear(); var m ...
- YAML语言简明教程
编程免不了要写配置文件,如果你还在用xml/ini/json,就有点过时了,怎么写配置也是一门学问. YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便. 本文介绍 YAM ...
- Java自学-类和对象 包
Java中的 包 包: package 把比较接近的类,规划在同一个包下 步骤 1 : 把比较接近的类,规划在同一个包下 Hero,ADHero 规划在一个包,叫做charactor(角色) Item ...
- kvm第一章--概念