最小表示法 + KMP - String Problem - HDU - 3374

最小表示法 + 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<=106Time limit1000msMemory limit32768kB

题解:

难 点 在 于 求 最 大 / 最 小 表 示 出 现 的 次 数 , 原 串 复 制 一 遍 再 将 最 大 / 最 小 表 示 逐 一 匹 配 似 乎 会 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值