此题我写的是后缀数组SA解法,如果不会后缀数组的可以跳过本篇blog了。

参考文献:罗穗骞 2009集训队后缀数组论文

前记

最近学后缀数组,肝了不少题,也分出了后缀数组的几个题型,看这题没有后缀数组的解法,于是我决定来水一波。

注:思想正确,代码不一定正确。

分析题意

给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的,
求 R 的最大值。

其实就是求字符串L的连续重复子串。连续重复子串就是后缀数组的一个题型。

算法分析

1、我们需要最大的R,就说明我们需要连续重复子串的子串长度最小,那我们就可以首先枚举子串的长度k。

2、如何判断枚举出的子串是否符合题意,为L的连续重复子串。相信学过后缀数组的大家一定知道如何求最长公共前缀,我在这里简要提一下。

最长公共前缀

定义&&性质

一、

Suf(i)为字符串S的从i位开始的后缀。

例:S="LAHAKIOI"

Suf(0)="LAHAKIOI".Suf(4)="AKIOI".(字符串从0开始)

二、

height[i]为Suf(SA[i])和Suf(SA[i-1])的最长公共前缀

三、

h[i]=height[rank[i]],也就是 Suf(i)和在它前一名的后缀的最长公共前
缀。

h数组有以下性质:
h[i]≥h[i-1]-1

具体证明这里不给出,如果有需要可以看我blog里的后缀数组全讲。

四、

Suf(j)和Suf(k)的最长公共前缀为(height[rank[j]+1],height[rank[j]+2],height[rank[j]+3],……,height[rank[k]])的最小值。

具体证明依然不给出,有需要可以看我的blog。


正所谓我们使用后缀数组求出了SA数组和Rank数组,我们想要求最长公共前缀,就要高效求出height数组。

求height数组,我们可以根据h数组的性质(三),对于每一个后缀和他上一个的字符串,我们不需要从头开始寻找他们的最长公共前缀,这样时间复杂度高达O(n^2),我们可以直接从h[i-1]-1处开始判断,因为根据h数组的性质,这两个字符串的前h[i-1]-1位一定是相同的。

这样时间复杂度降到O(n).

这里可能大家看的不是很懂,不过代码比较简单,比较容易懂:

void get_height(){      //求height数组int k=0;for(int i=0;i<n;i++){if(k)k--;       //h数组可以直接用一个计数器代替int j=sa[rank[i]-1];if(rank[i]-1==-1)continue;  //因为我的排名从0开始,所以排名是0时要特判while(s[i+k]==s[j+k])k++;   //从k处找最长公共前缀height[rank[i]]=k;          //记录height数组}
}

那我们求出了最长公共前缀就可以判断长度为k的子串是否满足为连续最长子串。

判断长度为k的子串是否满足为连续最长子串

1、首先,我们要判断字符串长度n是否能整除k,如果不能就显然不行。

2、再看Suf(0)到Suf(k)的最长公共前缀是否为n-k。前面根据性质四,我们可以知道Suf(0)到Suf(k)的最长公共前缀,但每一次的时间都为O(n),整体下来时间复杂度十分高。

但我们可以看到Suf(0)是固定的,所以我们可以预处理出只需求出 height 数组中的每一个数到height[rank[0]]之间的最小值记为ans数组即可。

全部代码:

#include<string>
#include<stdio.h>
#include<string.h>
#include<iostream>
#define maxn 300001
using namespace std;
char s[maxn];
int n,sa[maxn],rank[maxn],newRK[maxn],key2[maxn],sum[maxn],height[maxn],k;
int level;
void get_sum(int m){for(int i=0;i<=m;i++) sum[i]=0;for(int i=0;i<n;i++) sum[rank[i]]++;for(int i=0;i<m;i++) sum[i]+=sum[i-1];
}
bool cmp(int x,int y,int L){if(rank[x]!=rank[y])return false;if((x+L>=n&&y+L<n)||(x+L<n&&y+L>=n))return false;if(x+L>=n&& y+L>=n) return true;return rank[x+L] == rank[y+L];
}
void get_height(){      //求height数组int k=0;for(int i=0;i<n;i++){if(k)k--;       //h数组可以直接用一个计数器代替int j=sa[rank[i]-1];if(rank[i]-1==-1)continue;  //因为我的排名从0开始,所以排名是0时要特判while(s[i+k]==s[j+k])k++;   //从k处找最长公共前缀height[rank[i]]=k;          //记录height数组}
}
void Suffix_Sort(){         //SA板子for(int i=0;i<n;i++) rank[i]=s[i];get_sum(356);for(int i=n-1;i>=0;i--)sa[--sum[rank[i]]]=i;int w=1,m=max(n,356);while(w<n){int p=0;for(int i=n-w;i<n;i++)key2[p++]=i;  //第二关键字越界排前for(int i=0;i<n;i++)if(sa[i]>=w)key2[p++]=sa[i]-w;//如果当前长度有第一关键字就记录//以上按第二关键字排序get_sum(m);for(int i=n-1;i>=0;i--){int j=key2[i];sa[--sum[rank[j]]]=j;}//以上按第一关键字排序,直接覆盖之前的sa数组,不需要再开一个key1newRK[sa[0]]=0;level=1;for(int i=1;i<n;i++){if(cmp(sa[i-1],sa[i],w))newRK[sa[i]]=level-1;elsenewRK[sa[i]]=level++;}for(int i=0;i<n;i++)rank[i]=newRK[i];//以上计算长度2*w的rank数组if (level==n)break;w<<=1;}
}
int main(){while(1){int ans[maxn];memset(sa,0,sizeof(sa));memset(height,0,sizeof(height));memset(ans,0,sizeof(ans));memset(rank,0,sizeof(rank));scanf("%s",s);n=strlen(s);if(s[0]=='.')break;Suffix_Sort();get_height();//下面求ans数组int a=rank[0],minx=10000000;for(int i=a;i>=1;i--){minx=min(minx,height[i]);ans[sa[i-1]]=minx;}minx=10000000;for(int i=a+1;i<=n;i++){minx=min(minx,height[i]);ans[sa[i]]=minx;}for(int i=1;i<=n;i++){if(n%i==0){if(ans[i]==n-i){printf("%d\n",n/i);break;}}}}
}

谢谢观赏

转载于:https://www.cnblogs.com/hyfhaha/p/10678022.html

题解 UVA10298 【Power Strings】相关推荐

  1. ( KMP 求循环节的个数)Power Strings -- poj -- 2406

    链接: http://poj.org/problem?id=2406 Power Strings Time Limit:3000MS     Memory Limit:65536KB     64bi ...

  2. POJ 2406 Power Strings (KMP) kmp循环节

    版权声明:本文为博主原创文章,未经博主允许不得转载. Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions ...

  3. Power Strings POJ - 2406(求一串字符串中有多少个循环节)

    题意: 有一串字符串,问求出有多少个循环节连续重复组成,即可以用KMP直接求出循环节有多少个字符组成.答案就是l/next[l](刚开始理解错题意,认为是找出最多的重复子串) 题目 Given two ...

  4. 【POJ - 2406】Power Strings (KMP,最小循环节)

    题干: Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc ...

  5. D - Power Strings POJ - 2406

    Given two strings a and b we define ab to be their concatenation. For example, if a = "abc" ...

  6. Power Strings

    题目连接 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 using nam ...

  7. poj2406 Power Strings

    这题只是简单的KMP 算法. 只是有一点需要注意的就是当最后一个的大小是 len % (len - next[len])不够除的时候, 要直接判断是1, 不用继续计算.其他的就是裸的求next Vie ...

  8. 【POJ2406】Power Strings(KMP)

    problem 求每个字符串的最短循环子串,输出循环次数 solution 任何一个字符串的[1,Next[n]]与[n-Next[n],n]一定是匹配的. 那么如果n%(n-Next[n])==0, ...

  9. hash进阶:使用字符串hash乱搞的姿势

    前言 此文主要介绍hash的各种乱搞方法,hash入门请参照我之前这篇文章 不好意思hash真的可以为所欲为 在开头先放一下题表(其实就是我题解中的hash题目qwq) 查询子串hash值 必备的入门 ...

最新文章

  1. ubuntu安裝opencv3.4.1
  2. sass 安装配置和使用
  3. mysql和oracle区别总结(二)
  4. 【C#】ADO .Net Entities Framework使用查询语句时遇到的错误
  5. window环境搭建go语言运行环境
  6. python制作u盘病毒_十行代码--用Python写一个USB病毒!
  7. tesseract 使用说明
  8. CSDN 总部落户长沙,共建中国开发者产业中心城市!
  9. 2017-2018-1 20155315 《信息安全系统设计基础》实验五 通讯协议设计
  10. c语言中判断一个数是几位数 并顺序输出,统计数字n是个几位数,并将其逆序和顺序输出...
  11. 天空的颜色 454
  12. 工商总局:将对网店卖家身份进行全面普查
  13. Shell - cp
  14. TesterHome android app 编写历程(三)
  15. 8代处理器安装服务器系统,第八代cpu怎么安装win7
  16. 界面今日头条:2018年中国旅游城市排行榜
  17. Udacity优达学城 TensorFlow笔记2-对服饰图像分类
  18. CobaltStrike加载插件
  19. 品牌商业模式调研竞品市场分析方案模板ppt
  20. 如何由Xubuntu桌面系统还原至Ubuntu系统?

热门文章

  1. 关于批量插入数据之我见(100万级别的数据,mysql) (转)
  2. 厉害了,如何通过双 key 来解决缓存并发问题?
  3. 那一顿,我撸串撸懂了云计算!
  4. Netty 在 Dubbo 中是如何应用的?
  5. 程序员需要能show出来!
  6. Spring 框架用到的 9 个设计模式汇总!
  7. 一个多线程死锁案例,如何避免及解决死锁问题?
  8. Java 线程池艺术探索
  9. 鸿蒙发布的意义,华为鸿蒙正式发布!“鸿蒙”是什么意思?
  10. html的li浮动之后往下移动,多个li浮动后居中显示问题