最小表示法 + KMP - String Problem - HDU - 3374
题意:
多 组 测 试 用 例 , 每 组 包 括 一 个 字 符 串 。 要 求 这 个 字 符 串 的 最 小 表 示 和 最 大 表 示 第 一 次 出 现 的 位 置 以 及 出 现 的 次 数 。 多组测试用例,每组包括一个字符串。\\要求这个字符串的最小表示和最大表示第一次出现的位置以及出现的次数。 多组测试用例,每组包括一个字符串。要求这个字符串的最小表示和最大表示第一次出现的位置以及出现的次数。
Sample Input:
abcder
aaaaaa
ababab
Sample Output:
1 1 6 1
1 6 1 6
1 3 2 3
数据范围:
字 符 串 长 度 n < = 1 0 6 。 T i m e l i m i t : 1000 m s , M e m o r y l i m i t : 32768 k B 字符串长度n<=10^6。\\Time \ limit:1000 ms,Memory \ limit:32768 kB 字符串长度n<=106。Time limit:1000ms,Memory limit:32768kB
题解:
难 点 在 于 求 最 大 / 最 小 表 示 出 现 的 次 数 , 原 串 复 制 一 遍 再 将 最 大 / 最 小 表 示 逐 一 匹 配 似 乎 会 T L E 。 事 实 上 , 因 为 整 个 字 符 串 被 视 为 一 个 环 , 我 们 可 以 把 任 何 位 置 的 字 符 视 作 开 头 或 结 尾 , 因 此 , 任 何 一 个 位 置 开 始 的 字 符 串 出 现 的 次 数 都 是 相 等 的 。 那 么 我 们 可 以 将 问 题 转 化 为 求 任 意 位 置 开 始 的 字 符 串 循 环 节 的 个 数 , 每 个 循 环 节 对 应 一 个 相 同 字 符 串 的 起 点 。 难点在于求最大/最小表示出现的次数,原串复制一遍再将最大/最小表示逐一匹配似乎会TLE。\\事实上,因为整个字符串被视为一个环,我们可以把任何位置的字符视作开头或结尾,\\因此,任何一个位置开始的字符串出现的次数都是相等的。\\那么我们可以将问题转化为求任意位置开始的字符串循环节的个数,每个循环节对应一个相同字符串的起点。 难点在于求最大/最小表示出现的次数,原串复制一遍再将最大/最小表示逐一匹配似乎会TLE。事实上,因为整个字符串被视为一个环,我们可以把任何位置的字符视作开头或结尾,因此,任何一个位置开始的字符串出现的次数都是相等的。那么我们可以将问题转化为求任意位置开始的字符串循环节的个数,每个循环节对应一个相同字符串的起点。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e6+10;
char str[N];
int ne[N],n,m,ans1,ans2,cnt;
void get_next(char *str)
{
int i=0,j=-1,n=strlen(str);
ne[i]=j;
while(i<n){
if(j==-1 || str[i]==str[j]) ne[++i]=++j;
else j=ne[j];
}
}
int get_M(int flag)
{
int p1=0,p2=1,k=0;
while(p1<n&&p2<n&&k<n)
{
int tt=(str[(p1+k)%n]-str[(p2+k)%n]);
if(tt==0) k++;
else
{
if(!flag)
{
if(tt<0) p2+=k+1;
else p1+=k+1;
}
else
{
if(tt<0) p1+=k+1;
else p2+=k+1;
}
if(p1==p2) p2++;
k=0;
}
}
return min(p1,p2);
}
int main()
{
while(~scanf("%s",str))
{
ans1=ans2=cnt=0;
n=strlen(str);
get_next(str);
ans1=get_M(0)+1,ans2=get_M(1)+1;
if(n%(n-ne[n])==0) cnt=n/(n-ne[n]);
else cnt=1;
printf("%d %d %d %d\n",ans1,cnt,ans2,cnt);
}
return 0;
}