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; }
没有AC不了的题,只有不努力的ACMER!