Boring counting HDU - 3518 (后缀自动机)
Boring counting
\]
题意
给出一个字符串,求出其中出现两次及以上的子串个数,要求子串之间不可以重合。
思路
在 \(SAM\) 上对于节点 \(i\) ,其包含的子串长度范围为 \(\left[maxlen\left(father\right)+1,maxlen\left(i\right) \right]\),在考虑节点\(i\)的 \(endpos\),设出现的最左位置为 \(left\),最右位置为 \(right\),如果我们可以得到 \(left\) 和 \(right\),我们就可以进行如下的讨论:
- 首先明确 \(right-left\) 是同一子串两次出现位置最大距离,我们考虑在这个距离中,可以不重合的放下多少子串。
若 \(right-left \geq maxlen(i)\),距离足够大放下节点 \(i\) 可以表示的最长子串。这说明对于节点 \(i\) 包含的所有子串,都能满足不重合的出现两次。一共有 \(maxlen(i)-maxlen(father)\) 种子串符合条件。
若 \(right-left \leq maxlen(father)\),此时距离太小,无法放下节点 \(i\) 可以表示的最短子串。这说明对于节点 \(i\) 包含的所有子串,都无法满足不重合的出现两次。
若 \(maxlen(father) < right-left < maxlen(i)\), 此时距离只够放下其中的一部分子串。这时候容易得到,可以放下的子串的长度范围为 \(\left[maxlen(father)+1,right-left\right]\),也就是有 \(right-left-maxlen(father)\) 种子串符合条件。
综合上面三种情况,整理起来就是
- 若 \(right-left \leq maxlen(father)\),对答案贡献0。
- 否则,对答案贡献 \(min(right-left,maxlen(i)) - maxlen(father)\)。
那么如何得到 \(left\)和\(right\)?
- 对于 \(left\),每个子串第一次出现的位置,一定就是他的 \(left\)。
- 对于 \(right\),因为 \(endpos(i) \in endpos(father)\),所以将每个节点的 \(left\) 往其 \(father\) 上更新最大值,就是 \(father\) 的 \(right\),如此倒着求 \(right\)。
/***************************************************************
> File Name : a.cpp
> Author : Jiaaaaaaaqi
> Created Time : 2019年05月23日 星期四 00时06分46秒
***************************************************************/
#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>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e3 + 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 fa, len;
int left, right;
void init() {
mes(next, 0);
fa = len = left = right = 0;
}
} node[maxn<<1];
vector<int> vv[maxn<<1];
int sz, last;
void init() {
sz = last = 1;
node[sz].init();
}
void insert(int k, int id) {
int p = last, np = last = ++sz;
node[np].init();
node[np].len = node[p].len + 1;
node[np].left = node[np].right = id;
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[nq].left = node[q].left;
node[nq].right = node[q].right;
node[np].fa = node[q].fa = nq;
for(; p&&node[p].next[k]==q; p=node[p].fa)
node[p].next[k] = nq;
}
}
}
bool vis[maxn<<1];
void dfs(int u) {
if(vis[u]) return ;
vis[u] = true;
for(auto v : vv[u]) {
dfs(v);
node[u].right = max(node[u].right, node[v].right);
}
}
void build() {
for(int i=1; i<=sz; i++) vv[i].clear();
for(int i=2; i<=sz; i++) {
vv[node[i].fa].push_back(i);
}
mes(vis, 0);
dfs(1);
}
int finalans;
void DFS(int u) {
if(vis[u]) return ;
vis[u] = true;
for(auto v : vv[u]) {
DFS(v);
int l = node[v].left, r = node[v].right;
if(r-l > node[u].len) {
finalans += min(node[v].len, r-l) - node[u].len;
}
}
return ;
}
int solve() {
finalans = 0;
mes(vis, 0);
DFS(1);
return finalans;
}
} sam;
char s[maxn];
int main() {
while(scanf("%s", s+1)) {
if(s[1] == '#') break;
sam.init();
int len = strlen(s+1);
for(int i=1; i<=len; i++) {
sam.insert(s[i]-'a'+1, i);
}
sam.build();
// for(int i=1; i<=sam.sz; i++) {
// printf("%d left = %d right = %d\n", i, sam.node[i].left, sam.node[i].right);
// }
printf("%d\n", sam.solve());
}
return 0;
}
Boring counting HDU - 3518 (后缀自动机)的更多相关文章
- Boring counting HDU - 3518 后缀自动机
题意: 对于给出的字符串S, 长度不超过1000, 求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次 题解: 将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出 ...
- Boring counting HDU - 3518 (后缀数组)
Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...
- POJ 3518 (后缀自动机)
POJ 3518 Boring Problem : 给一个串S,询问串S有多个子串出现至少两次且位置不重叠. Solution : 对S串建立后缀自动机,再建立后缀树,dfs一遍统计处每个结点的子树中 ...
- HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)
http://acm.hdu.edu.cn/showproblem.php?pid=5442 题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样 ...
- HDU 4436 (后缀自动机)
HDU 4436 str2int Problem : 给若干个数字串,询问这些串的所有本质不同的子串转换成数字之后的和. Solution : 首先将所有串丢进一个后缀自动机.由于这道题询问的是不同的 ...
- HDU 4622 (后缀自动机)
HDU 4622 Reincarnation Problem : 给一个串S(n <= 2000), 有Q个询问(q <= 10000),每次询问一个区间内本质不同的串的个数. Solut ...
- HDU 4416 (后缀自动机)
HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...
- HDU 5442 后缀自动机+kmp
题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针 比赛一直因为处理最小位置出错,一结束就想 ...
- hdu 6208(后缀自动机、或者AC自动机
题意:给你n个字符串,问你是否存在一个字符串可以从中找到其他n-1个字符串. 思路:其实很简单,找到最长的那个字符串对他进行匹配,看是否能匹配到n-1个字符串. 可以用AC自动机或者后缀自动机做,但是 ...
随机推荐
- Centos 使用kubeadm安装Kubernetes 1.15.3
本来没打算搞这个文章的,第一里面有瑕疵(没搞定的地方),第二在我的Ubuntu 18 Kubernetes集群的安装和部署 以及Helm的安装 也有安装,第三 和社区的问文章比较雷同 https:// ...
- webUI框架miniUI,easyUI,extJS,Bootstrap简介及简单部署
本文为大家讲解的是webUI框架miniUI,easyUI,extJS,Bootstrap简介及简单部属,感兴趣的同学参考下 ExtJS是一种主要用于创建前端用户界面,是一个基本与后台技术无关的前端a ...
- 如何通过 IntelliJ IDEA 来提升 Java8 Stream 的编码效率
本文翻译整理自:https://winterbe.com/posts/2015/03/05/fixing-java-8-stream-gotchas-with-intellij-idea 作者:@Wi ...
- VMwarm下安装ubuntu的一些问题
1.终端无法输入中文的原因(未实践) 原文地址 2.Windows10下VMwarm(V15.5)和ubuntu14.04实现复制文件(已经实践) 转载路径
- C# 调用Access数据库关于like模糊查询的写法
在access查询视图中要使用"*"做模糊匹配,但是在程序中要用%来匹配.在access中:NEIBUBH like '*1234*'在程序中:NEIBUBH like '%123 ...
- div css字间距
div:nth-child(1){ color: #FFFFFF; font-size: 13px; font-weight: bold; margin-bottom: 25px; letter-sp ...
- 爬虫之selenium模块;无头浏览器的使用
一,案例 爬取站长素材中的图片:http://sc.chinaz.com/tupian/gudianmeinvtupian.html import requests from lxml import ...
- 百度云人脸识别API人脸库管理
from urllib import request import base64 import requests import re import json import urllib impor ...
- Httpd服务进阶知识-LAMP源码编译安装
Httpd服务进阶知识-LAMP源码编译安装 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 想必大家都知道,动态资源交给fastcgi程序处理,静态资源依旧由httpd服务器处理 ...
- HTML-Parser
背景:需求需要把 html 字符串转成 DOM 对象树或者 js 对象树,然后进行一些处理/操作.htmlparser 这个库还行,但是对 attribute 上一些特殊属性值转换不行,同时看了看`开 ...