Substrings

\[Time Limit: 100ms\quad Memory Limit: 1572864 kB
\]

题意

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

  1. SPOJ NSUBSTR (后缀自动机)

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

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

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

  3. 长度为x的本质不同的串的出现次数 SPOJ - NSUBSTR 后缀自动机简单应用

    题意: 长度为x的本质不同的串的出现次数 题解: 先处理出每一个节点所对应的子串出现的次数 然后取max就好了 #include <set> #include <map> #i ...

  4. Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))

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

  5. Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)

    Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题 ...

  6. SPOJ LCS 后缀自动机

    用后缀自动机求两个长串的最长公共子串,效果拔群.多样例的时候memset要去掉. 解题思路就是跟CLJ的一模一样啦. #pragma warning(disable:4996) #include< ...

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

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

  8. SPOJ - LCS 后缀自动机入门

    LCS - Longest Common Substring A string is finite sequence of characters over a non-empty finite set ...

  9. SPOJ LCS 后缀自动机找最大公共子串

    这里用第一个字符串构建完成后缀自动机以后 不断用第二个字符串从左往右沿着后缀自动机往前走,如能找到,那么当前匹配配数加1 如果找不到,那么就不断沿着后缀树不断往前找到所能匹配到当前字符的最大长度,然后 ...

随机推荐

  1. Effective.Java第23-33条(泛型相关)

    23.  类结构层次优于标签类 有时你会碰到一个类,它的实例有一个或多个风格,并且包含一个tag属性表示实例的风格.例如,如下面的类表示一个圆或者矩形: public class Figure { / ...

  2. listener中@Autowired无法注入bean的一种解决方法

    背景:使用监听器处理业务,需要使用自己的service方法: 错误:使用@Autowired注入service对象,最终得到的为null: 原因:listener.fitter都不是Spring容器管 ...

  3. JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态

    JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态  2017年10月25日  Jet Ma  JavaPlatform JVM故障分析系列系列文章 JVM故障分析系列之一: ...

  4. Puppet自动化管理配置

    Puppet:开源系统配置和管理工具 随着虚拟化和云计算技术的兴起,计算机集群的自动化管理和配置成为了数据中心运维管理的热点.对于 IaaS.Paas.Saas 来说,随着业务需求的提升,后台计算机集 ...

  5. Centos7安装Tomcat7,并上传JavaWeb项目

    一.需要的工具(其他连接工具也行) 1.Xshell 2.XFTP 1.1首先将Tomcat7的压缩文件利用XFTP上传到Centos7系统上的 /etc/local/tomcat中 1.2 解压文件 ...

  6. Java3-5年经验面试题总结

    记录一下本次找工作所遇到的一些高频面试题,第一次找java工作,感觉比面试.net舒服多了,17年的时候出去找.net工作,由于在公司做的东西用到的技术少,除了mvc和ef,其他没啥问的,就追着项目问 ...

  7. VS 对话框控件的Tab顺序问题

    我们先来直观的看看各个控件的Tab顺序吧.打开“Resource View”视图,然后在资源中找到对话框IDD_ADDITION_DIALOG,双击ID后中间客户区域出现其模板视图.在主菜单中选择“F ...

  8. jQuery的内部运行机制和原理

    jQuery的优点: jQuery是一个非常优秀的JavaScript库,与Prototype,YUI,Mootools等众多的Js类库相比,它剑走偏锋,从Web开发实用的角度出发,抛除了其它Lib中 ...

  9. android中fragment卡顿的原因

    首页的ViewPager有十几个Fragment,在快速切换的时候,容易产生卡顿现象. 二.分析当ViewPager切换到当前的Fragment时,Fragment会加载布局并显示内容,如果用户这时快 ...

  10. Android源码分析(四)-----Android源码编译及刷机步骤

    一 : 获取源码: 每个公司服务器地址不同,以如下源码地址为例: http://10.1.14.6/android/Qualcomm/msm89xx/branches/msm89xx svn环境执行: ...