【字符串】后缀数组

 参考文章:

数据结构 —— 字符串:后缀数组_Jetiaime的博客-CSDN博客(算法代码)

后缀数组_KonjakLAF的博客-CSDN博客(应用+例题)

板子:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
const int inf=1<<30;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,k;
char s[N];
int m,sa[N],cnt[N],rk[N],id[N],px[N],oldrk[N];inline bool cmp(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];
}
inline void getsa(){//初始化 m=10;for(int i=1;i<=n;i++)cnt[rk[i]=s[i]-'0']++;for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];//for(int i=1;i<=9;i++)printf("cnt[%d]:%d\n",i,cnt[i]);for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); //倍增for(int k=1;k<=n;k<<=1){//后缀长度 int idx=0;for(int i=n;n-i<k;i--)id[++idx]=i;for(int i=1;i<=n;i++)if(sa[i]>k)id[++idx]=sa[i]-k;//按后一半排序的后缀memset(cnt,0,sizeof(cnt));for(int i=1;i<=n;i++)cnt[px[i]=rk[id[i]]]++;for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];for(int i=n;i;i--)sa[cnt[px[i]]--]=id[i];idx=0;swap(oldrk,rk);for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i],sa[i-1],k)?idx:++idx;m=idx;if(n==m)break;//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); }//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); 
}
int val[N],len;
inline void add(ll x){ll pre=x;for(int i=1;i<=len;i++){if(!pre)break;val[i]+=pre;pre=val[i]/10;val[i]%=10;}while(pre)val[++len]=pre%10,pre/=10;
}
int main(){scanf("%d%d",&n,&k);scanf("%s",s+1);getsa();ll res=0;len=n-k;for(int i=n;i;i--){if(sa[i]<=k+1){//sa[i]--sa[i]+n-k//printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); for(int j=sa[i],anj=len;j<=sa[i]+n-k-1;j++,anj--){//printf("s[%d]:%c %d\n",j,s[j],s[j]-'0');//res=res*10+int(s[j]-'0');val[anj]=s[j]-'0';}for(int j=1;j<sa[i];j++)res+=s[j]-'0';for(int j=sa[i]+n-k;j<=n;j++)res+=s[j]-'0';//printf("%lld",res);add(res);for(int i=len;i;i--)printf("%d",val[i]);break;}}return 0;
}

例题: 

例1:P3809 【模板】后缀排序 - 洛谷 (luogu.com.cn) 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int inf=1<<30;
const ll INF=0x3f3f3f3f3f3f3f3f;
char s[N];
int l1,l2,n;
int idx,m,sa[N],rk[N],oldrk[N],px[N],id[N],c[N];
bool cmp(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];
}
void getsa(){//初始化m=150;for(int i=1;i<=n;i++)c[rk[i]=s[i]]++;for(int i=1;i<=m;i++)c[i]+=c[i-1];//for(int i=1;i<=m;i++)printf("c[%d]%d\n",i,c[i]);for(int i=n;i;i--)sa[c[rk[i]]--]=i;//for(int i=1;i<=n;i++)printf("sa[%d]%d %s\n",i,sa[i],s+sa[i]);//倍增for(int k=1;k<=n;k<<=1){idx=0;for(int i=n;n-i<k;i--)id[++idx]=i;for(int i=1;i<=n;i++)if(sa[i]>k)id[++idx]=sa[i]-k;memset(c,0,sizeof(c));for(int i=1;i<=n;i++)c[px[i]=rk[id[i]]]++;for(int i=1;i<=m;i++)c[i]+=c[i-1];for(int i=n;i;i--)sa[c[px[i]]--]=id[i];swap(rk,oldrk);idx=0;for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i],sa[i-1],k)?idx:++idx;if(idx==n)break;m=idx;//for(int i=1;i<=n;i++)printf("sa[%d]%d %s\n",i,sa[i],s+sa[i]);} 
}
int ht[N];
void geth(){for(int i=1,k=0;i<=n;i++){if(k)k--;while(s[i+k]==s[sa[rk[i]-1]+k])k++;ht[rk[i]]=k;}
}inline void read(int &x){int f=1;x=0;char ch=getchar();while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch&15);ch=getchar();}x*=f;
}
inline void write(int x){if(x<0){putchar('-');x=-x;}if(x>9)write(x/10);putchar('0'+x%10);
}
int main(){scanf("%s",s+1);n=strlen(s+1);getsa();geth();for(int i=1;i<=n;i++)printf("%d ",sa[i]);return 0;
}

例2:数字串 -matiji 

题解:找到最大的n-k位数

eg. 6 2 121312

样例:
6 2
121312
排序后:
12
121312
1312
2
21312
312

倒序遍历找到最大的n-k位数

注意:*1.由于字符串长度最大1e6,会爆ll,所以存储每一位的数字然后输出

           *2.getsa()函数中没有 if(n==m)break; 会超时

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
const int inf=1<<30;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,k;
char s[N];
int m,sa[N],cnt[N],rk[N],id[N],px[N],oldrk[N];inline bool cmp(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];
}
inline void getsa(){//初始化 m=10;for(int i=1;i<=n;i++)cnt[rk[i]=s[i]-'0']++;for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];//for(int i=1;i<=9;i++)printf("cnt[%d]:%d\n",i,cnt[i]);for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); //倍增for(int k=1;k<=n;k<<=1){//后缀长度 int idx=0;for(int i=n;n-i<k;i--)id[++idx]=i;for(int i=1;i<=n;i++)if(sa[i]>k)id[++idx]=sa[i]-k;//按后一半排序的后缀memset(cnt,0,sizeof(cnt));for(int i=1;i<=n;i++)cnt[px[i]=rk[id[i]]]++;for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];for(int i=n;i;i--)sa[cnt[px[i]]--]=id[i];idx=0;swap(oldrk,rk);for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i],sa[i-1],k)?idx:++idx;m=idx;if(n==m)break;//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); }//for(int i=1;i<=n;i++)printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); 
}
int val[N],len;
inline void add(ll x){ll pre=x;for(int i=1;i<=len;i++){if(!pre)break;val[i]+=pre;pre=val[i]/10;val[i]%=10;}while(pre)val[++len]=pre%10,pre/=10;
}
int main(){scanf("%d%d",&n,&k);scanf("%s",s+1);getsa();ll res=0;len=n-k;for(int i=n;i;i--){if(sa[i]<=k+1){//sa[i]--sa[i]+n-k//printf("sa[%d]:%d %s\n",i,sa[i],s+sa[i]); for(int j=sa[i],anj=len;j<=sa[i]+n-k-1;j++,anj--){//printf("s[%d]:%c %d\n",j,s[j],s[j]-'0');//res=res*10+int(s[j]-'0');val[anj]=s[j]-'0';}for(int j=1;j<sa[i];j++)res+=s[j]-'0';for(int j=sa[i]+n-k;j<=n;j++)res+=s[j]-'0';//printf("%lld",res);add(res);for(int i=len;i;i--)printf("%d",val[i]);break;}}return 0;
}

例3:乐曲主题 - 洛谷 (最长不重叠公共子串)

转调后仍相同则差值相同,此时只需找不重叠的最长公共子串

可转化为不同后缀的最长公共前缀,且不同后缀的公共前缀不重叠 

后缀数组计算时cnt[a[i]]计数,而差值a[i]可能为负数如 1-88,在此给每一个a[i]+90 

有子串长度为 4 时 "主题" 长度为 5 

二分答案,答案变成判定性问题。

将 height [ i ]分为连续的组,如果有连续的一段 height≥mid ,且 max(sai)−min(sai)>mid

说明存在长度为 mid且不重叠的重复子串。

*对 height [ i ] 分组的方法很重要。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e3+5;
const int inf=1<<30;
const ll INF=0x3f3f3f3f3f3f3f3f;inline void read(ll &x){ll f=1;x=0;char ch=getchar();while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch&15);ch=getchar();}x*=f;
}
inline void write(int x){if(x<0){putchar('-');x=-x;}if(x>9)write(x/10);putchar('0'+x%10);
}
int n,a[N];
int m,sa[N],rk[N],oldrk[N],px[N],id[N],idx,ht[N],c[N];
bool cmp(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];
}
void getsa(){//初始化 m=180;for(int i=1;i<=n;i++)c[rk[i]=a[i]]++;for(int i=2;i<=m;i++)c[i]+=c[i-1];for(int i=n;i;i--)sa[c[rk[i]]--]=i;//倍增for(int k=1;k<=n;k<<=1){idx=0;for(int i=n;n-i<k;i--)id[++idx]=i;for(int i=1;i<=n;i++)if(sa[i]>k)id[++idx]=sa[i]-k;memset(c,0,sizeof(c));for(int i=1;i<=n;i++)c[px[i]=rk[id[i]]]++;for(int i=2;i<=m;i++)c[i]+=c[i-1];for(int i=n;i;i--)sa[c[px[i]]--]=id[i];//更新rk swap(rk,oldrk);idx=0;for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i],sa[i-1],k)?idx:++idx;if(idx==n)break;m=idx;} 
}
void geth(){for(int i=1,k=0;i<=n;i++){if(k)k--;while(a[i+k]==a[sa[rk[i]-1]+k])k++;ht[rk[i]]=k;}
}
int chk(int x){int mn=sa[1],mx=sa[1];for(int i=2;i<=n;i++){if(ht[i]<x){mn=mx=sa[i];}else {mn=min(mn,sa[i]);mx=max(mx,sa[i]);if(mx-mn>x)return 1;}}return 0;
}
/*
a 0
aabcdd 1
aabckm 4
aabcko 5
bac 0
此时ht为1 4 5的是一组 sa[i]max-sa[i]min+1 >= mid则不重复    
*/
int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<n;i++)a[i]=a[i+1]-a[i]+90;a[n--]=0;/*转调后仍相同则差值相同,此时只需找不重叠的最长公共子串可转化为不同后缀的最长公共前缀,且不同后缀的公共前缀不重叠 后缀数组计算时cnt[a[i]]计数,而差值a[i]可能为负数如 1-88,在此给每一个a[i]+90 有子串长度为 4 时 "主题" 长度为 5 */getsa();geth();/* 二分查找最长长度 -> 转化为判定问题 *///for(int i=1;i<=n;i++)printf("a[%d]%d\n",i,a[i]);printf("\n");//for(int i=1;i<n;i++)printf("sa[%d]%d a[%d]%d ht[%d]%d\n",i,sa[i],sa[i],a[sa[i]],i,ht[i]);int l=0,r=n,res=0;while(l<=r){int mid=(l+r)/2;if(chk(mid))res=mid,l=mid+1;else r=mid-1;//printf("l%d r%d res%d\n",l,r,res);}printf("%d",res>=4?res+1:0);return 0;
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/85144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据分享】2005-2022年全国民航机场客货吞吐量和起降架次数据

机场是一个城市对外联系的重要渠道&#xff0c;机场的旅客吞吐量和货物吞吐量是体现一个城市对外联系程度的重要指标。 本次我们给大家分享的是2005-2022年我国民航机场的旅客吞吐量、货邮吞吐量、起降架次数据。数据格式为Excel和Shp两种格式。数据坐标为WGS1984。原始数据来…

MySQL常考知识点

MySQL常考知识点 索引的基本原理索引设计的原则事务的基本特性和隔离级别什么是MVCC简述MyISAM和InnoDB的区别Explain语句结果中各个字段分表表示什么索引覆盖是什么最左前缀原则是什么B树和B树的区别&#xff0c;为什么Mysql使⽤B树Mysql锁有哪些&#xff0c;如何理解Mysql慢查…

腾讯面试题:无网络环境,如何部署Docker镜像?

亲爱的小伙伴们&#xff0c;大家好&#xff01;我是小米&#xff0c;很高兴再次和大家见面。今天&#xff0c;我要和大家聊聊一个特别有趣的话题——腾讯面试题&#xff1a;无网络环境&#xff0c;如何部署Docker镜像&#xff1f;这可是一个技术含量颇高的问题哦&#xff01;废…

nodejs 如何在npm发布自己的包 <记录>

一、包结构 必要结构&#xff1a; 一个包对应一个文件夹&#xff08;文件夹名不是包名&#xff0c;但最好与包名保持一致&#xff0c;包名以package.json中的name为主&#xff09;包的入口文件index.js包的配置文件package.json包的说明文档README.md 二、需要说明的文件 1.配…

PyTorch实战:卷积神经网络详解+Python实现卷积神经网络Cifar10彩色图片分类

目录 前言 一、卷积神经网络概述 二、卷积神经网络特点 卷积运算 单通道&#xff0c;二维卷积运算示例 单通道&#xff0c;二维&#xff0c;带偏置的卷积示例 带填充的单通道&#xff0c;二维卷积运算示例 Valid卷积 Same卷积 多通道卷积计算 1.局部感知域 2.参数共…

软件测试的理论基础1

软件的生命周期 可行性研究和计划&#xff08;立项&#xff09; 需求分析 概要设计&#xff08;测试计划&#xff09; 详细设计&#xff08;测试方案&#xff09; 实现&#xff08;开发阶段&#xff1b;包含单元测试&#xff09; 组装测试&#xff08;集成测试&#xff09; 确…

【MT7628AN】IOT | MT7628AN OpenWRT开发与学习

IOT | MT7628AN OpenWRT开发与学习 时间:2023-06-21 文章目录 `IOT` | `MT7628AN` `OpenWRT`[开发与学习](https://blog.csdn.net/I_feige/article/details/132911634?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132911634…

空间(蓝桥杯)

空间 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小蓝准备用 256MB 的内存空间开一个数组&#xff0c;数组的每个元素都是 32 位 二进制整数&#xff0c;如果不考虑程序占用的空间和维护内存需要的辅助空间&#xff0c;…

上PICO,沉浸式观看亚运直播,参与跨国界游戏竞技

备受瞩目的杭州第19届亚运会&#xff0c;将于9月23日正式开幕。据悉&#xff0c;这也是有史以来项目最多的一届亚运会&#xff0c;除部分传统奥运项目外&#xff0c;还包含武术、藤球、板球、克柔术、柔术等亚洲特色项目&#xff0c;以及霹雳舞、电子竞技等深受年轻人喜爱的新兴…

完成flex布局与float布局

当涉及到布局时&#xff0c;Flex布局和Float布局是两种不同的方法&#xff0c;它们分别用于实现不同的布局需求。下面我将为你展示如何使用这两种方法来完成布局。 1. 使用Flex布局&#xff1a; Flex布局是一种强大的布局方法&#xff0c;特别适用于创建响应式和灵活的布局。…

Mojo编程语言是AI人工智能的新的编程语言

Mojo是Chris Lattner的创业公司Modular开发的一种新的编程语言&#xff0c;旨在统一AI基建和异构计算。Mojo被认为是Python的超集&#xff0c;兼容Python生态&#xff0c;但添加了系统编程和编译期优化的特性&#xff0c;以提高性能和部署效率。Mojo基于MLIR&#xff0c;可以支…

debian终端快捷键设置

为了方便使用图形化debian&#xff0c;快捷调出shell终端是提升工作学习效率的最重要的一步。 1.首先点击右上角&#xff0c;选择设置 2.点击键盘&#xff0c;选择快捷键&#xff0c;并创建自定义快捷键 3.点击添加快捷键 4.根据图中提示创建快捷键 Name: Terminal Command…

promise回顾和总结(温故知新)

文章目录 promise回顾和总结&#xff08;温故知新&#xff09;1.promise语法 promise回顾和总结&#xff08;温故知新&#xff09; 参考: https://juejin.cn/post/6844903604009041928 1.promise语法 Promise编程的核心思想是如果数据就绪(promised)&#xff0c;那么(then)做点…

Android Jetpack Compose之UI的重组和自动刷新

1.概述 我们都知道&#xff0c;在传统的View中&#xff0c;若要改变UI&#xff0c;需要我们修改View的私有属性&#xff0c;比如要修改一个TextView的文字&#xff0c;我们需要通过它的setText(“xxx”)方法去修改。而Compose 则是通过重组来刷新UI。在之前的状态管理的文章中…

MyBatis的动态 SQL、代理机制与多级缓存

MyBatis的动态 SQL、代理机制与多级缓存 前言一、动态 SQL二、代理机制三、多级缓存最后 前言 MyBatis 是一个开源的 Java 持久层框架&#xff0c;它通过 XML 或注解的方式将 SQL 语句与 Java 对象进行映射。相比于传统的 JDBC 操作数据库&#xff0c;MyBatis 简化了很多重复的…

uni-app获取地理位置

在uni-app中&#xff0c;可以通过uni.getLocation()方法获取地理位置。具体步骤如下&#xff1a; 在uni-app项目中的manifest.json文件中&#xff0c;添加需要获取地理位置的权限&#xff1a; {"mp-weixin": {"appid": "...","permission…

【CSS】画个三角形或圆形或环

首先通过调整边框&#xff0c;我们可以发现一些端倪 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style>.box{width: 150px;height:150px;border: 50px solid black;}</style&g…

[JAVEee]SpringBoot项目的创建

SpringBoot可以更好的开发Spring项目,本文章将使用idea社区版来演示创建项目的过程与注意事项. SpringBoot的优点 SpringBoot中内置快速添加依赖的功能,能够便捷的集成各种框架,帮助开发.内置运行容器,无需配置Tomcat容器等其他web容器,可直接进行项目的部署与运行.更好的使用…

2023年中国研究生数学建模竞赛D题解题思路

为了更好的帮助大家第一天选题&#xff0c;这里首先为大家带来D题解题思路&#xff0c;分析对应赛题之后做题阶段可能会遇到的各种难点。 稍后会带来D题的详细解析思路&#xff0c;以及相关的其他版本解题思路 成品论文等资料。 赛题难度评估&#xff1a;A、B>C>E、F&g…

Git创建干净分支,本地操作不依赖任何分支

clone远程项目: git clone gittest.git查看分支: git branch -a创建新分支: git checkout --orphan test, 返回Switched to a new branch test删除当前项目文件夹下所有文件: git rm -rf .提交变更: git commit -m "new branch for test"查看分支: git branch -a, 发…