2016vijos 1-1 兔子的字符串(后缀数组 + 二分 + 哈希)
题意:
给出一个字符串,至多将其划分为n部分,每一部分取出字典序最大的子串ci,最小化 最大的ci
先看一个简化版的问题:
给一个串s,再给一个s的子串t,问能否通过将串划分为k个部分,使t成为划分后的s的字典序最大子串
#include<cstdio> #include<cstring> #include<algorithm>using namespace std;#define N 100001typedef long long LL;const int base=13331;int n,m; char s[N];int a[N]; int v[N]; int p,q=1,k; int sa[2][N],rk[2][N]; int h[N];unsigned long long Pow[N],has[N];pair<int,int>interval[N];void mul(int *sa,int*rk,int *SA,int *RK) {for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]] || rk[SA[i]+k]!=rk[SA[i-1]+k]); }void presa() {for(int i=1;i<=n;++i) v[a[i]]++;for(int i=1;i<=26;++i) v[i]+=v[i-1];for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); }void get_height() {int j,k=0;for(int i=1;i<=n;++i){j=sa[p][rk[p][i]-1];while(a[i+k]==a[j+k]) k++;h[rk[p][i]]=k;if(k) k--;} }void prehash() {Pow[0]=1;for(int i=1;i<=n;++i) Pow[i]=Pow[i-1]*base;for(int i=1;i<=n;++i) has[i]=has[i-1]*base+a[i]; }pair<int,int>select(LL k) {int now;LL sum=0;int l,r;for(int i=1;i<=n;++i) {now=interval[i].second-interval[i].first+1;if(sum+now>=k){l=sa[p][i];r=interval[i].first+k-sum-1;return make_pair(l,r);}sum+=now;} }unsigned long long get_hash(int l,int r) {return has[r]-has[l-1]*Pow[r-l+1]; }int cmp(pair<int,int>x,pair<int,int>y) {if(get_hash(x.first,x.second)==get_hash(y.first,y.second)) return 0;int Lx=x.second-x.first+1,Ly=y.second-y.first+1;int l=1,r=min(Lx,Ly),mid,tmp=0;while(l<=r){mid=l+r>>1;if(get_hash(x.first,x.first+mid-1)==get_hash(y.first,y.first+mid-1)) tmp=mid,l=mid+1;else r=mid-1;}if(tmp<min(Lx,Ly)) return s[x.first+tmp]<s[y.first+tmp] ? -1 : 1;return Lx<Ly ? -1 : 1; }bool check(pair<int,int>now) {int l=n,r=n,sum=1;while(l>=1)if(cmp(make_pair(l,r),now)==1) {if(l==r) return false;r=l;sum++;if(sum>m) return false;}else l--;return true; }void solve() {LL l=1,r=0;for(int i=1;i<=n;++i){interval[i].first=sa[p][i]+h[i];interval[i].second=n;r+=interval[i].second-interval[i].first+1;}LL mid,tmp;pair<int,int>now;while(l<=r){mid=l+r>>1;now=select(mid);if(check(now)) tmp=mid,r=mid-1;else l=mid+1;}now=select(tmp);l=now.first; r=now.second;for(int i=l;i<=r;++i) putchar(s[i]); } int main() {freopen("string.in","r",stdin);freopen("string.out","w",stdout);scanf("%d",&m);scanf("%s",s+1);n=strlen(s+1);for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1;presa();get_height();prehash();solve(); }
转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8981700.html
2016vijos 1-1 兔子的字符串(后缀数组 + 二分 + 哈希)相关推荐
- 洛谷 P4094 [HEOI2016/TJOI2016]字符串 后缀数组+二分+主席树
题目链接 后缀数组 题目分析: sa[i] – 第i小的后缀的编号 rank[i] --编号为i的后缀排第几: height[i] – 第i和第i-1的最长lcp最长公共前缀: 1.二分答案,答案肯定 ...
- BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...
- HDU - 5030 Rabbit's String(后缀数组+二分)
题目链接:点击查看 题目大意:给出一个字符串,现在要求将其分为不大于k个连续的子串,对于每个子串求出字典序最大的子串,现在要求所有子串的最大子串的最大值最小,输出这个最大子串 题目分析:最大值最小,标 ...
- HDU - 5008 Boring String Problem(后缀数组+二分)
题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
- [BZOJ4310]跳蚤-后缀数组-二分答案
跳蚤 Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择 ...
- bzoj3277 串 (后缀数组+二分答案+ST表)
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
- UVa 11107 (后缀数组 二分) Life Forms
利用height值对后缀进行分组的方法很常用,好吧,那就先记下了. 题意: 给出n个字符串,求一个长度最大的字符串使得它在超过一半的字符串中出现. 多解的话,按字典序输出全部解. 分析: 在所有输入的 ...
- POJ - 1226 Substrings(后缀数组+二分)
题目链接:点击查看 题目大意:给出n个字符串,求出n个字符串中或者在他们翻转过来的字符串中,出现的最长公共子串的长度 题目分析:说白了就是求n个字符串中的最长公共子串的变形,而这个变形也相当简单,只是 ...
- SPOJ - PHRASES Relevant Phrases of Annihilation(后缀数组+二分)
题目链接:点击查看 题目大意:给出n个字符串,求出n个字符串中的最长公共子串,且该字串必须在每个字符串中出现至少两次且不能重叠 题目分析:结合之前整理过的: 一个字符串中两个不重叠的重复子串的最大长度 ...
最新文章
- python后端开发框架加密_Flask框架实现的前端RSA加密与后端Python解密功能详解
- 苹果如何使用神经网络在点云中做对象检测
- HDOJ 1070 排序 水
- html缩进快捷键_Mac技巧|如何高效使用苹果便笺?利用便笺快捷键快速完成操作!
- python函数修饰器_Python函数装饰器指南
- c++11-template template Parameter
- jmx JVM监测工具使用
- 将undefault和null的数据转换成bool类型的数据 使用!!
- 前端学习(2547):数据代理
- 在pycharm中自定义模板代码,快速输出固定代码块
- 教育部统考 计算机应用,9月教育部统考《计算机应用基础》试卷一附答案.doc
- 网络应用瑞士军刀——Zentyal(4 常用命令)
- Python selenium 实现大麦网自动购票过程
- 任务栏右键工具栏里的语言栏没有的修复.reg
- Selenium中的鼠标单击事件
- MPFC++ wrapper by Pavel
- SOUI总结之盒子模型
- c# socket套接字
- b2b2c微信小程序商城源码
- 算法——钻石金字塔(动态规划+贪心)