后缀数组练习1:不可重叠最长重复子串

这道题在之前,一定要先看一下我之前在后缀数组博客里面提到的最长公共前缀

1467: 后缀数组1:不可重叠最长重复子串

poj1743

时间限制: 2 Sec  内存限制: 128 MB
提交: 207  解决: 81
[提交] [状态] [讨论版] [命题人:admin]
题目描述

题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:

    1.长度至少为5个音符。

    2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)

    3.重复出现的同一主题不能有公共部分。


【输入格式】

输入N(1<=N<=20000)

输入N个正整数,有多组数据,N为0时结束。

【输出格式】

输出满足条件的最大长度
【样例】
输入:

30
25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
82 78 74 70 66 67 64 60 65 80
0

输出:

  然后如果你了解了最长公共前缀,那么我们就提一下这道题和最长公共前缀有什么大关系

求字符串中至少重复1次或者且不重叠的最长长度
这里重复指的是两个字符串对应位置相减的差相等
比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的
思路:既然要求变化一样,那么可以让原数组前后相减,然后利用后缀数组height的性质求子串最长公共前缀即可

这题是要在求出相邻音高之差之后找不重叠(无公共部分)的最长的重复出现过至少两次的串,
也就是在height数组中找到一个连续段,其各项均大于d且sa数组中的对应段中最大值最小值之差要大于d。找到最大的d即可。
d符合一个性质,就是小的d都满足,大的d都不满足。用二分法找分界线即可。

然后题意也非常清楚了,我们就直接讲方法:最长公共前缀+后缀数组+二分

二分是因为我们要找最大的长度,所以要用二分

然后还有一个要注意的就是:最长公共前缀求出来的是高度差,也就是说我们最后结果要加1,因为如果有n个点,就只有n-1个间隙,所以的话要加1才是我们需要的点数

代码的实现

(注释版,可能最主要的就是提及一下高度差获取的函数的使用吧,如果认真看论文应该也没有什么问题)

  1 /*求字符串中至少重复1次或者且不重叠的最长长度
  2 这里重复指的是两个字符串对应位置相减的差相等
  3 比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的
  4 思路:既然要求变化一样,那么可以让原数组前后相减,然后利用后缀数组height的性质求子串最长公共前缀即可*/
  5  
  6 /*这题是要在求出相邻音高之差之后找不重叠(无公共部分)的最长的重复出现过至少两次的串,
  7 也就是在height数组中找到一个连续段,其各项均大于d且sa数组中的对应段中最大值最小值之差要大于d。找到最大的d即可。
  8 d符合一个性质,就是小的d都满足,大的d都不满足。用二分法找分界线即可。*/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<cstdlib>
 12 #include<algorithm>
 13 #include<cmath>
 14 #include<iostream>
 15 using namespace std;
 16 int sa[20010],Rank[20010],rsort[20010];
 17 int a[20010],cnt[20010],pos[20010],n,height[20010];/*处理最长公共前缀*/
 18 /*定义 height[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公
 19 共前缀,也就是排名相邻的两个后缀的最长公共前缀*/
 20 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
 21 void get_sa(int n,int m)/*倍增模版*/
 22 {
 23     int k=1,p=0,len;
 24     for(int i=1;i<=n;i++) Rank[i]=a[i];
 25     memset(rsort,0,sizeof(rsort));
 26     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
 27     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
 28     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
 29     for(int k=1;k<n;k<<=1)
 30     {
 31         len=0;
 32         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
 33         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
 34         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
 35         memset(rsort,0,sizeof(rsort));
 36         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
 37         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
 38         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
 39         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
 40         p=1; Rank[sa[1]]=1;
 41         for(int i=2;i<=n;i++)
 42         {
 43             if(!cmp(sa[i],sa[i-1],k)) p++;
 44             Rank[sa[i]]=p;
 45         }
 46         if(p==n) break; m=p;
 47     }
 48     a[0]=0; sa[0]=0;
 49 }
 50 void get_he(int n)/*最长公共前缀*/
 51 {
 52     int j,k=0;
 53     for(int i=1;i<=n;i++)
 54     {
 55         j=sa[Rank[i]-1];/*寻找相邻的最长公共前缀*/
 56         if(k) k--;/*h[i]>=h[i-1]+1*/
 57         while(a[j+k]==a[i+k]) k++;/*寻找下一位*/
 58         height[Rank[i]]=k;/*h[i]=height[rank[i]]*/
 59     }
 60 }
 61 bool check(int k,int n)
 62 {
 63     for(int i=2;i<=n;i++)
 64     {
 65         if(height[i]<k) continue;/*如果他们的高度差小于我们设定的高度差,就找下一个*/
 66         else/*否则的话*/
 67         {
 68             for(int j=i-1;j>=1;j--)/*相邻的*/
 69             {
 70                 if(abs(sa[i]-sa[j])>=k) return true;/*满足条件,返回答案*/
 71                 if(height[j]<k) break;/*不满足就退出j循环*/
 72             }
 73         }
 74     }
 75     return false;
 76 }
 77 int main() 
 78 {
 79     while(scanf("%d",&n)!=EOF && n)
 80     {
 81         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 82         int maxx=-9999999;
 83         for(int i=1;i<n;i++)
 84         { 
 85             a[i]=a[i+1]-a[i]+88;
 86             if(maxx<a[i]) maxx=a[i];/*更新最大值*/
 87         }
 88         a[n]=0; n--;
 89         get_sa(n,maxx); get_he(n);
 90         int l=1,r=n,ans=0;
 91         while(l<=r)/*二分寻找答案*/
 92         {
 93             int mid=(l+r)/2;
 94             if(check(mid,n))
 95             {
 96                 ans=mid;
 97                 l=mid+1;
 98             }
 99             else r=mid-1;
100         }
101         if(ans<4) printf("0\n");
102         else printf("%d\n",ans+1);
103         /*因为我们求的是高度差,也就是间隙,所以如果有n个点,就有n-1个间隙,所以最后结果要增加1*/
104     }
105     return 0;
106 }
Tristan Code 注释版

(非注释版,如果你完全看懂了论文,就没有必要看注释版的了)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<iostream>
 7 using namespace std;
 8 int sa[20010],Rank[20010],rsort[20010];
 9 int a[20010],cnt[20010],pos[20010],n,h[20010];
10 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
11 void get_sa(int n,int m) 
12 {
13     int k=1,p=0,len;
14     for(int i=1;i<=n;i++) Rank[i]=a[i];
15     memset(rsort,0,sizeof(rsort));
16     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
17     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
18     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
19     for(int k=1;k<n;k<<=1)
20     {
21         len=0;
22         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
23         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
24         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
25         memset(rsort,0,sizeof(rsort));
26         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
27         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
28         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
29         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
30         p=1; Rank[sa[1]]=1;
31         for(int i=2;i<=n;i++)
32         {
33             if(!cmp(sa[i],sa[i-1],k)) p++;
34             Rank[sa[i]]=p;
35         }
36         if(p==n) break; m=p;
37     }
38     a[0]=0; sa[0]=0;
39 }
40 void get_he(int n)
41 {
42     int j,k=0;
43     for(int i=1;i<=n;i++)
44     {
45         j=sa[Rank[i]-1];
46         if(k) k--;
47         while(a[j+k]==a[i+k]) k++;
48         h[Rank[i]]=k;
49     }
50 }
51 bool check(int k,int n)
52 {
53     for(int i=2;i<=n;i++)
54     {
55         if(h[i]<k) continue;
56         else
57         {
58             for(int j=i-1;j>=1;j--)
59             {
60                 if(abs(sa[i]-sa[j])>=k) return true;
61                 if(h[j]<k) break;
62             }
63         }
64     }
65     return false;
66 }
67 int main() 
68 {
69     while(scanf("%d",&n)!=EOF && n)
70     {
71         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
72         int maxx=-9999999;
73         for(int i=1;i<n;i++)
74         { 
75             a[i]=a[i+1]-a[i]+88;
76             if(maxx<a[i])maxx=a[i];
77         }
78         a[n]=0; n--;
79         get_sa(n,maxx); get_he(n);
80         int l=1,r=n,ans=1;
81         while(l<=r)
82         {
83             int mid=(l+r)/2;
84             if(check(mid,n))
85             {
86                 ans=mid;
87                 l=mid+1;
88             }
89             else r=mid-1;
90         }
91         if(ans<4) printf("0\n");
92         else printf("%d\n",ans+1);
93     }
94     return 0;
95 }
Tristan Code 非注释版

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值