Boring counting

\[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \]

题意

给出一个字符串,求出其中出现两次及以上的子串个数,要求子串之间不可以重合。

思路

对字符串后缀数组,然后枚举子串长度 \(len\),若某一段连续的 \(sa[i]\) 的 \(lcp \geq len\),那么说明这一段内存在一个长度为 \(lcp\) 的子串,而我们只需要其中的前 \(len\) 部分,接下来只要找出这个子串出现的最左和最右位置,然后判断中间能否放下这个长度为 \(len\) 的子串就可以了,如果可以的话,就让 \(ans\)++。


\(Hint\)
这题还让我学到后缀数组的另一个细节,在构建后缀数组之前,要在末尾加上一个比所有字符都小的字符,因为在求 \(height\) 的时候需要判断 \(a[i+k]==a[j+k]\),否则这里可能会无限扩展下去。

/***************************************************************> File Name    : a.cpp> Author       : Jiaaaaaaaqi> Created Time : 2019年05月23日 星期四 22时40分17秒***************************************************************/#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 = 1e5 + 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;char s[maxn];
int a[maxn], sa[maxn], tp[maxn], tax[maxn], rk[maxn], height[maxn];void rsort(int n, int m) {for(int i=0; i<=m; i++) tax[i] = 0;for(int i=1; i<=n; i++) tax[rk[tp[i]]]++;for(int i=1; i<=m; i++) tax[i] += tax[i-1];for(int i=n; i>=1; i--) sa[tax[rk[tp[i]]]--] = tp[i];
}int cmp(int *f, int x, int y, int w) {return f[x]==f[y] && f[x+w]==f[y+w];
}void SA(int *a, int n, int m) {for(int i=1; i<=n; i++) rk[i] = a[i], tp[i] = i;rsort(n, m);for(int w=1, p=1, i; p<n; w<<=1, m=p) {for(p=0, i=n-w+1; i<=n; i++)    tp[++p] = i;for(i=1; i<=n; i++) if(sa[i] > w)   tp[++p] = sa[i]-w;rsort(n, m), swap(rk, tp);rk[sa[1]] = p = 1;for(i=2; i<=n; i++) rk[sa[i]] = cmp(tp, sa[i], sa[i-1], w) ? p : ++p;}int j, k=0;for(int i=1; i<=n; height[rk[i++]] = k)for(k = k ? k-1 : k, j=sa[rk[i]-1]; a[i+k]==a[j+k]; k++);
}int calc(int len) {int ans = 0;int mx, mn;mx = -inf, mn = inf;for(int i=2; i<=n; i++) {if(height[i]>=len) {mx = max(mx, max(sa[i], sa[i-1]));mn = min(mn, min(sa[i], sa[i-1]));} else {if(mx - mn >= len)  ans++;mx = -inf, mn = inf;}}if(mx - mn >= len)  ans++;return ans;
}int main() {while(scanf("%s", s+1)) {if(s[1] == '#') break;n = strlen(s+1);s[++n] = 2;for(int i=1; i<=n; i++) {a[i] = s[i];}SA(a, n, 260);// for(int i=1; i<=n; i++) {//     printf("sa[%d] = %d\n", i, sa[i]);// }int ans = 0;for(int i=1; i<=(n+1)/2; i++) {ans += calc(i);}printf("%d\n", ans);}return 0;
}

转载于:https://www.cnblogs.com/Jiaaaaaaaqi/p/10915328.html

Boring counting HDU - 3518 (后缀数组)相关推荐

  1. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  2. hdu 6194 后缀数组

    题意:一个字符串,查询恰好出现k次的子串的数目 思路:后缀数组在height上进行操作.我们直接枚举长度为k的区间求min值,但是要注意的是直接这么算是会重复的,同时也可能超过k次,这样我们就需要把枚 ...

  3. HDU 6194 后缀数组+单调栈

    题意: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 找到一个字符串中恰好出现k次的子串的数目. 思路: 计算出height数组,根据heig ...

  4. hdu 4416 后缀数组

    昨天做1007,做到吐血,一直wa,原来是结果是超int的,好容易算错啊,刚刚好觉得是10位,没超, 但是那是10位0,还有最高为1啊,又范这种低级错误了,引以为戒,不要在范. 先说一下我的做法,利用 ...

  5. hdu 3948(后缀数组+RMQ)

    题意:求一个串中有多少不同的回文串. 分析:这一题的关键是如何去重,我表示我现在还没理解为什么这样去重,先放这里过两天再看!! //不同回文子串数目 #include <iostream> ...

  6. 后缀数组 --- HDU 3518 Boring counting

    Boring counting Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3518 Mean: 给你一个字符串,求:至少出 ...

  7. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

  8. HDU - 5008 Boring String Problem(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...

  9. HDU 6194 string string string :后缀数组+单调队列 | 后缀自动机

    题意:给出一个字符串,求出出现了恰好k次的子串的个数. 题解:恰好k次 = 至少k次 - 至少k+1次.答案转化为求至少出现k次的子串个数统计.构造好后缀数组以及很重要的Height数组之后.用一个k ...

最新文章

  1. 告别「灭霸式审稿」,IJCAI-21 的投稿者爽到家!
  2. 最新!中国内地大学ESI排名出炉:313所高校上榜!
  3. 超好用的Swift 4.0 字符截取快速便捷方法
  4. 系统管理模块_部门管理_设计(映射)本模块中的所有实体并总结设计实体的技巧_懒加载异常问题_树状结构...
  5. [unreal4入门系列之七] UE4中的Actor类和Pawn类
  6. 网站后台管理界面设计的一些想法
  7. 上标3下标6算法_插入排序算法导学案
  8. access 合并多行字符串_八种方法玩转字符串合并,这篇文章全都给你讲明白!...
  9. C++易被忽略的知识点:移动语义 左值右值
  10. 应用SELinux中的目标策略限制进程运行
  11. ISO9000软件使用管理办法
  12. html z-dext优先级顺序,$ext{1D/1D}$ 动态规划的三种优化
  13. 【以前的空间】vijos 1720 阿狸的打字机
  14. 渗透-N种反弹shell方法
  15. sp_help 查看表结构 alter column修改字段长度
  16. vc设备工程师_工程/设备工程师简历工作经历填写样本
  17. 手把手教学linux上扩容和缩减swap分区。
  18. 【P2P网络】磁力链接转换为种子文件 magnet to torrent .
  19. git文件夹不显示绿勾
  20. 网站备案后一定要做的一件事【否则罚款5千元~1万元】

热门文章

  1. exchange2003备份与恢复
  2. 区块链概念:Hash 算法
  3. helm部署仓库中没有的包_Kubernetes的Helm软件包管理器简介
  4. 同步等待 异步等待_异步/等待和承诺的解释
  5. Java怎么定义图片公共路径_【Java】springboot配置图片访问路径
  6. mysql中日期判断的函数_MySql判断汉字、日期、数字的函数
  7. 2021年甘肃省副高考试成绩查询,2021年甘肃卫生资格考试成绩查询-中国卫生人才网...
  8. 零基础学习java,这些书一定要看!
  9. oracle触发器初始化,oracle – 触发器无法初始化变量
  10. debian手动安装java两种方法