P5341 [TJOI2019]甲苯先生和大中锋的字符串
题目背景
TJOI2019 D2T2
源文件名:substring.*
时间限制: 1s 内存限制: 128M
题目描述
大中锋有一个长度为 nn 的字符串,他只知道其中的一个子串是祖上传下来的宝藏的密码。但是由于字符串很长,大中锋很难将这些子串一一尝试。
这天大中锋找到甲苯先生算命,但是甲苯先生说:“天机不可泄漏”。
在大中锋的苦苦哀求下,甲苯先生告诉大中锋:“密码是在字符串中恰好出现了 kk 次的子串”。
但是大中锋不知道该怎么做,在大中锋再三的恳求下,甲苯先生看其真诚,又告诉他:“在恰好出现了 kk 次的子串中,你去按照字串的长度分类,密码就在数量最多的那一类里”。
大中锋为了尝试这个密码,想让你帮忙找出子串长度出现次数最多的长度数(如果有多个输出最长长度)。
输入格式
第一行一个正整数 TT ,表示有 TT 组测试数据。
接下来 TT 行每行包含一个字符串和一个正整数 kk 。
输出格式
一共输出 TT 行,每行一个整数表示在出现 kk 次的子串中出现次数的最多的长度。如果不存在子串出现 kk 次,则输出 -1−1 。
输入输出样例
6 aab 1 abc 1 aaaa 2 abab 2 ababacc 2 abab 4
2 1 3 1 2 -1
说明/提示
数据说明
对于第一个数据:其中子串 b, aa, ab, aabb,aa,ab,aab 均只出现一次,其中长度为 11 的子串出现了 11 次,长度为 22 的子串出现了 22 次,长度为 33 的子串出现了 11 次。所以答案为 22 。
对于第二个数据:其中子串 a, b, c, ab, bc, abca,b,c,ab,bc,abc 均只出现一次,其中长度为 11 的子串出现了 33 次,长度为 22 的子串出现了 22 次,长度为 33 的子串出现了 11 次。所以答案为 11 。
对于第三个数据:其中子串 aaaaaa 出现二次,长度为 33 的子串出现了 11 次,其他长度均没有。所以答案为 33 。
对于第四个数据:其中子串 a, b, aba,b,ab 出现二次,其中长度为 11 的子串出现了 22 次,长度为 22 的子串出现了 11 次。所以答案为 11 。
对于第五个数据:其中子串 b, c, ab, bab,c,ab,ba 出现二次,其中长度为 11 的子串出现了 22 次,长度为 22 的子串出现了 22 次。所以答案为 22 。
对于第六个数据:其中子串没有出现四次。所以本题的本题的答案为 -1−1 。
数据范围
对于 20\%20% 的数据, 1\leq k\leq n\leq 101≤k≤n≤10
对于 100\%100% 的数据, 1\leq n\leq 10^5,1 \leq T \leq 100,\sum n \leq 3 * 10^61≤n≤105,1≤T≤100,∑n≤3∗106 ,输入的字符串中仅包含小写英文字母。
题解
出现$k$次的子串就是$SAM$上$right$集合大小为$k$的点。找出这些点然后用一个前缀和覆盖就可以求出哪个长度出现次数最多了。
代码
1 #include<bits/stdc++.h> 2 #define N (200009) 3 #define LL long long 4 using namespace std; 5 6 char s[N]; 7 int n,k,sum[N]; 8 9 struct SAM { 10 int p,q,np,nq,last,cnt; 11 int son[N][28],fa[N],step[N],right[N]; 12 int wt[N],od[N]; 13 SAM() {last=cnt=1;} 14 15 void Clear() { 16 p=q=np=nq=0; 17 last=cnt=1; 18 memset(son,0,sizeof(son)); 19 memset(fa,0,sizeof(fa)); 20 memset(step,0,sizeof(step)); 21 memset(right,0,sizeof(right)); 22 memset(wt,0,sizeof(wt)); 23 memset(od,0,sizeof(od)); 24 } 25 void Insert(int x) { 26 p=last; np=last=++cnt; step[np]=step[p]+1; right[np]=1; 27 while(!son[p][x] && p) son[p][x]=np, p=fa[p]; 28 if (!p) fa[np]=1; 29 else { 30 q=son[p][x]; 31 if (step[q]==step[p]+1) fa[np]=q; 32 else { 33 nq=++cnt; step[nq]=step[p]+1; 34 memcpy(son[nq],son[q],sizeof(son[q])); 35 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 36 while (son[p][x]==q) son[p][x]=nq, p=fa[p]; 37 } 38 } 39 } 40 void Init() { 41 int len=strlen(s); 42 for (int i=1; i<=cnt; ++i) wt[step[i]]++; 43 for (int i=1; i<=len; ++i) wt[i]+=wt[i-1]; 44 for (int i=cnt; i>=1; --i) od[wt[step[i]]--]=i; 45 for (int i=cnt; i>=1; --i) right[fa[od[i]]]+=right[od[i]]; 46 for (int i=1; i<=cnt; ++i) { 47 if (right[i]!=k) continue; 48 sum[step[i]+1]--; sum[step[fa[i]]+1]++; 49 } 50 int ans=0,cnt=0; 51 for (int i=1; i<=n; ++i) sum[i]+=sum[i-1]; 52 for (int i=n; i>=1; --i) if (sum[i]>cnt) cnt=sum[i], ans=i; 53 cout<<(ans==0?-1:ans)<<endl; 54 } 55 }SAM; 56 57 int main() { 58 int T; 59 cin>>T; 60 while (T--) { 61 memset(sum,0,sizeof(sum)); 62 SAM.Clear(); 63 cin>>s>>k; 64 n=strlen(s); 65 for (int i=0; i<n; ++i) SAM.Insert(s[i]-'a'); 66 SAM.Init(); 67 } 68 }
原文地址:https://www.cnblogs.com/refun/p/15026853.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android Studio实现简单计算器APP
- 基于PHP实现微信小程序客服消息功能
- python gstreamer实现视频快进/快退/循环播放功能
- php tpl模板引擎定义与使用示例
- ThinkPHP5&5.1框架关联模型分页操作示例
- Android实现简易计算器(可以实现连续计算)
- PHP实现提高SESSION响应速度的几种方法详解
- ThinkPHP5.1框架数据库链接和增删改查操作示例
- 新版Flutter集成到已有Android项目的实现
- PHP基于session.upload_progress 实现文件上传进度显示功能详解
- Android实现加法计算器
- Android使用Realm数据库实现App中的收藏功能(代码详解)
- Android实现简单加法计算器
- Android实现两个数相加功能
- 基于Android studio3.6的JNI教程之ncnn之语义分割ENet