xdoj1012 字符串哈希

xdoj1012 字符串哈希

 

1012: 重复序列

时间限制: 1 Sec  内存限制: 128 MB
提交: 149  解决: 15
[提交][状态][讨论版]

题目描述

为了让密码变得更长,fpcsong在密码的末端增加了一些无意义内容。为了能够记住密码,增加的内容往往是重复序列。例如下列密码

xduacm2015_mimayaochangchangchang

的末端有一重复序列,即"chang"重复3次。现在,给你一个串s,请你确定一个串p和数x,使得p非空,x>1,px(指串p重复x次)为s的后缀。若有多个可能的解,输出x最大的解。若仍有多解,输出|p|(p的长度)最大的解。若无解,输出-1。

输入

多组数据,每组数据1行,包含一个串s。s中只有字母(大小写敏感),数字,下划线。|s|<=400000。

输出

对于每组数据,输出1行,若有解输出串p和整数x,用空格分割。若无解输出-1。

样例输入

xduacm2015_mimayaochangchangchang
orzorzorzorz
Orzorzorzorz
orzorz_diaodiaodiaodiao
we_orz_tencent_light_light
ooooooooooops

样例输出

chang 3
orz 4
orz 3
diao 4
_light 2
-1

这道水题kmp可以做,后缀数组也可以做,字符串哈希也可以做。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

typedef unsigned long long ull;
const ull x=123LL;
const int maxn=4000100;
ull H[maxn],xp[maxn];
ull Hash[maxn];
char s[maxn];
int n;
struct Ans
{
    int cnt,len;
    friend bool operator<(Ans A,Ans B)
    {
        if(A.cnt<B.cnt) return 1;
        if(A.cnt==B.cnt) return A.len<B.len;
        return 0;
    }
};

void Init()
{
    H[n]=0;
    for(int i=n-1;i>=0;i--) H[i]=H[i+1]*x+(s[i]-'a');
    xp[0]=1;
    for(int i=1;i<=n;i++) xp[i]=xp[i-1]*x;
}

Ans solve(int L)
{
    int i=n-L,j=n-2*L;
    if(j<0) return {-1,-1};
    Hash[i]=H[i]-H[i+L]*xp[L];
    Hash[j]=H[j]-H[j+L]*xp[L];
    int cnt=1;
    while(j>=0&&Hash[i]==Hash[j]){
        cnt++;
        j-=L;
        if(j>=0) Hash[j]=H[j]-H[j+L]*xp[L];
    }
    if(cnt==1) return {-1,-1};
    return {cnt,L};
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>s){
        n=strlen(s);
        Init();
        Ans ans={-1,-1};
        for(int i=1;i<=n;i++){
            Ans tmp=solve(i);
            if(ans<tmp) ans=tmp;
        }
        if(ans.cnt!=-1){
            for(int i=n-ans.len;i<n;i++) printf("%c",s[i]);
            printf(" ");
        }
        printf("%d",ans.cnt);
        puts("");
    }
    return 0;
}
View Code

 

posted @ 2015-09-15 13:46  __560  阅读(347)  评论(0编辑  收藏  举报