后缀数组之hihocoder 重复旋律1-4
蒟蒻知道今天才会打后缀数组,而且还是nlogn^2的。。。但基本上还是跑得过的;
重复旋律1:
二分答案,把height划分集合,height<mid就重新划分,这样保证了每个集合中的LCP>=mid,套路板子题
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1000050;
int gi(){
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,a[N],k;
struct data{
int fir,sec,id;
}x[N];
bool cmp(const data &a,const data &b){
if(a.fir==b.fir) return a.sec<b.sec;
else return a.fir<b.fir;
}
void work2(){
rk=1;y[x[1].id]=rk;
for(int i=2;i<=len;i++){
if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
y[x[i].id]=rk;
}
}
void work(){
sort(x+1,x+1+len,cmp);work2();
for(int i=1;i<=len;i<<=1){
for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
sort(x+1,x+1+len,cmp);work2();
if(rk==len) break;
}
}
void get_height(){
int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
for(int i=1;i<=len;i++){
if(kk) kk--;
int j=sa[rnk[i]-1];
while(a[i+kk]==a[j+kk]) kk++;
height[rnk[i]]=kk;
}
}
bool check(int mid){
int ret=1,size=1;
for(int i=2;i<=len;i++){
if(height[i]<mid) ret=max(ret,size),size=1;
else size++;
}
return ret>=k;
}
int main(){
len=gi();k=gi();for(int i=1;i<=len;i++) a[i]=gi();
for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i];
work();for(int i=1;i<=len;i++) sa[y[i]]=i;
get_height();int l=0,r=len;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
重复旋律2:
和上题差不多,二分答案,把height划分集合,维护集合中的最左端和最右端,判断两端相减>=mid;
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1000050;
int gi(){
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,a[N],k;
struct data{
int fir,sec,id;
}x[N];
bool cmp(const data &a,const data &b){
if(a.fir==b.fir) return a.sec<b.sec;
else return a.fir<b.fir;
}
void work2(){
rk=1;y[x[1].id]=rk;
for(int i=2;i<=len;i++){
if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
y[x[i].id]=rk;
}
}
void work(){
sort(x+1,x+1+len,cmp);work2();
for(int i=1;i<=len;i<<=1){
for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
sort(x+1,x+1+len,cmp);work2();
if(rk==len) break;
}
}
void get_height(){
int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
for(int i=1;i<=len;i++){
if(kk) kk--;
int j=sa[rnk[i]-1];
while(a[i+kk]==a[j+kk]) kk++;
height[rnk[i]]=kk;
}
}
bool check(int mid){
int minn=sa[1],maxn=sa[1];
for(int i=2;i<=len;i++){
if(height[i]<mid){
if(maxn-minn>=mid) return 1;
minn=maxn=sa[i];
}
minn=min(minn,sa[i]),maxn=max(maxn,sa[i]);
}
return 0;
}
int main(){
len=gi();for(int i=1;i<=len;i++) a[i]=gi();
for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i];
work();for(int i=1;i<=len;i++) sa[y[i]]=i;
get_height();int l=0,r=len;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
重复旋律3:
还是板子,把两个串用"#"分开,然后还是二分答案划分height集合
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1000050;
int gi(){
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,cor[N],num[3];
char ch[N],ch2[N],a[N];
struct data{
int fir,sec,id;
}x[N];
bool cmp(const data &a,const data &b){
if(a.fir==b.fir) return a.sec<b.sec;
else return a.fir<b.fir;
}
void work2(){
rk=1;y[x[1].id]=rk;
for(int i=2;i<=len;i++){
if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
y[x[i].id]=rk;
}
}
void work(){
sort(x+1,x+1+len,cmp);work2();
for(int i=1;i<=len;i<<=1){
for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
sort(x+1,x+1+len,cmp);work2();
if(rk==len) break;
}
}
void get_height(){
int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
for(int i=1;i<=len;i++){
if(kk) kk--;
int j=sa[rnk[i]-1];
while(a[i+kk]==a[j+kk]) kk++;
height[rnk[i]]=kk;
}
}
bool check(int mid){
memset(num,0,sizeof(num));num[cor[sa[1]]]++;
for(int i=2;i<=len;i++){
if(height[i]<mid){
if(num[1]&&num[2]) return 1;
memset(num,0,sizeof(num));
}
num[cor[sa[i]]]++;
}
return 0;
}
int main(){
scanf("%s",ch+1);scanf("%s",ch2+1);
int len1=strlen(ch+1),len2=strlen(ch2+1);len=len1+len2+1;
for(int i=1;i<=len1;i++) a[i]=ch[i],cor[i]=1;a[len1+1]='#';
for(int i=1;i<=len2;i++) a[len1+1+i]=ch2[i],cor[len1+1+i]=2;
for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i]-'a'+1;
work();for(int i=1;i<=len;i++) sa[y[i]]=i;
get_height();
int l=0,r=min(len1,len2);
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
重复旋律4:
真正的大火题。。。
首先暴力需要枚举长度L,以及串开始的位置i,则以i开始,循环长度为L的答案为1+lcp(i,i+L)/L,记为k(i,L);这个把图画一下还是很好理解的
优化的话可以只考虑L的整数倍上的位置,然后对于不在整数倍上的x,在他后面的最近的L的整数倍数为p,则k(x,L)不大于k(p,L)+1,
因为我们知道i和i+L的lcp,那么i+lcp和i+L+lcp是失配的,不然lcp还可以更长,所以在这里就gi了。
然后因为x和p相差不超过L,所以k的值顶多加1;
然后假设存在一个x使得k(x,L)==k(p,L)+1,那么x=i-L+lcp%L,这相当把失配位置往前挪(续..)了一个L,可以画图理解一下,所以只需要额外判断k(x,L)即可
然后
for(int L=1;L<=len;L++){
for(int i=L;i+L<=len;i+=L){
}
}
是一个经典的nlogn复杂度,很优秀。。。lcp的话就是height的rmq最小值即可,ST表即可。妙不可言
// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=200050;
int gi(){
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int sa[N],len,y[N],rk,rnk[N],height[N],ans,pre[N],pre2[N],ST[N][20];
char ch[N],ch2[N],a[N];
struct data{
int fir,sec,id;
}x[N];
bool cmp(const data &a,const data &b){
if(a.fir==b.fir) return a.sec<b.sec;
else return a.fir<b.fir;
}
void work2(){
rk=1;y[x[1].id]=rk;
for(int i=2;i<=len;i++){
if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
y[x[i].id]=rk;
}
}
void work(){
sort(x+1,x+1+len,cmp);work2();
for(int i=1;i<=len;i<<=1){
for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
sort(x+1,x+1+len,cmp);work2();
if(rk==len) break;
}
}
void get_height(){
int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
for(int i=1;i<=len;i++){
if(kk) kk--;
int j=sa[rnk[i]-1];
while(a[i+kk]==a[j+kk]) kk++;
height[rnk[i]]=kk;
}
}
void make_ST(){
pre[0]=1;for(int i=1;i<=16;i++) pre[i]=pre[i-1]<<1;
pre2[0]=-1;for(int i=1;i<=len;i++) pre2[i]=pre2[i>>1]+1;
for(int i=2;i<=len;i++) ST[i][0]=height[i];
for(int j=1;j<=16;j++)
for(int i=2;i<=len;i++){
if(i+pre[j]-1<=len){
ST[i][j]=min(ST[i][j-1],ST[i+pre[j-1]][j-1]);
}
}
}
int query(int l,int r){
int x=pre2[r-l+1];
return min(ST[l][x],ST[r-pre[x]+1][x]);
}
int LCP(int l,int r){
if(l>r) swap(l,r);
return query(l+1,r);
}
int main(){
scanf("%s",a+1);len=strlen(a+1);
for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i]-'a'+1;
work();for(int i=1;i<=len;i++) sa[y[i]]=i;
get_height();make_ST();
for(int L=1;L<=len;L++){
for(int i=L;i+L<=len;i+=L){
int lcp=LCP(rnk[i],rnk[i+L]);ans=max(ans,1+lcp/L);
ans=max(ans,LCP(rnk[i-L+lcp%L],rnk[i+lcp%L])/L+1);
}
}
printf("%d\n",ans);
return 0;
}
后缀数组之hihocoder 重复旋律1-4的更多相关文章
- 【简要题解】Hihocoder 重复旋律1-9简要题解
[简要题解]Hihocoder 重复旋律1-8简要题解 编号 名称标签 难度 1403 后缀数组一·重复旋律 Lv.4 1407 后缀数组二·重复旋律2 Lv.4 1415 后缀数组三·重复旋律3 L ...
- HihoCoder 重复旋律
あの旋律を何度も繰り返しでも.あの日見た光景を再現できない 无论将那段旋律重复多少次,也无法重现那一日我们看到的景象 もし切ないならば.時をまきもどしてみるかい? 若是感到惆怅的话,要试着让时光倒流吗 ...
- POJ 1743 Musical Theme 后缀数组 最长重复不相交子串
Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description ...
- 【SPOJ – REPEATS】 后缀数组【连续重复子串】
字体颜色如何 字体颜色 SPOJ - REPEATS 题意 给出一个字符串,求重复次数最多的连续重复子串. 题解 引自论文-后缀数组--处理字符串的有力工具. 解释参考博客 "S肯定包括了字 ...
- 牛客网多校训练第一场 I - Substring(后缀数组 + 重复处理)
链接: https://www.nowcoder.com/acm/contest/139/I 题意: 给出一个n(1≤n≤5e4)个字符的字符串s(si ∈ {a,b,c}),求最多可以从n*(n+1 ...
- 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)
模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...
- CodeForces - 113B Petr# (后缀数组)
应该算是远古时期的一道题了吧,不过感觉挺经典的. 题意是给出三一个字符串s,a,b,求以a开头b结尾的本质不同的字符串数. 由于n不算大,用hash就可以搞,不过这道题是存在复杂度$O(nlogn)$ ...
- hihoCoder 1403 后缀数组一·重复旋律(后缀数组+单调队列)
#1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...
- hihocoder #1419 : 后缀数组四·重复旋律4
#1419 : 后缀数组四·重复旋律4 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构 ...
随机推荐
- python学习笔记 python实现k-means聚类
# -*- coding: utf-8 -*- """ Created on Thu Mar 16 14:52:58 2017 @author: Jarvis " ...
- OC中只有重写没有重载
一.类的继承 Objective-c中类的继承与C++类似,不同的是Objective-c不支持多重继承,一个类只能有一个父类,单继承使Objective-c的继承关系很简单,易于管理程序. 二.方法 ...
- LoadRunner性能测试过程中报Error(-17998):Failed to get [param not passed in call] thread TLS entry.
最近与其他公司一起合作使用loadrunner11进行性能测试,在此过程中,遇到Error(-17998)的错误,从网上搜索,找到的答案基本上都是说没有定义事务,但检查所有测试代码,发现都已经定义了事 ...
- 数据库服务器---Qps
QPS(Query Per Second)意思为"每秒查询率",是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准.同时也代表一种计算 ...
- eclipse导入新项目后,运行时找不到主类解决办法
最近在学习多线程,今天下了一套源码,导入到eclipse里后,随便找了个带main()的类试了一下,找不到主类. 首先想到的解决办法是把工程clean一下,并没有用.去网上找了一个遍终于找到了管用的方 ...
- uva 1378 - A Funny Stone Game(组合游戏)
题目链接:uva 1378 - A Funny Stone Game 题目大意:两个人玩游戏,对于一个序列,轮流操作.每次选中序列中的i,j,k三个位置要求i<j≤k,然后arr[i]减1,对应 ...
- Cocos游戏引擎,让小保安成就大梦想
秦丕胜是大连的一位保安.与非常多自学成才的人一样,2010年,在考上日照职业技术学院一年后便退了学. 因为没有高学历.加上喜欢自由,他来到了大连成为了一名保安.从高中開始,秦丕胜就酷爱代码,他曾自豪地 ...
- Windows Azure系列-- 配置Azure Power Shell
1.下载Azure Power shell https://azure.microsoft.com/en-us/documentation/articles/powershell-install-co ...
- HDU-1828-Picture(线段树)
Problem Description A number of rectangular posters, photographs and other pictures of the same shap ...
- EventBus在Android中的简单使用
EventBus是一个方便与Android中各组件通信的开源框架,开源地址;https://github.com/greenrobot/EventBus.EventBus功能非常强大 ,今天在做一个功 ...