您的位置:首页 > 其它

【2012百度之星/资格赛】H:用户请求中的品牌

2012-05-29 22:20 435 查看
时间限制: 1000ms 内存限制: 65536kB

描述

馅饼同学是一个在百度工作,做用户请求(query)分析的同学,他在用户请求中经常会遇到一些很奇葩的词汇。在比方说“johnsonjohnson”、“duckduck”,这些词汇虽然看起来是一些词汇的单纯重复,但是往往都是一些特殊品牌的词汇,不能被拆分开。为了侦测出这种词的存在,你今天需要完成我给出的这个任务——“找出用户请求中循环节最多的子串”。

输入输入数据包括多组,每组为一个全部由小写字母组成的不含空格的用户请求(字符串),占一行。用户请求的长度不大于100,000。

最后一行输入为#,作为结束的标志。
输出对于每组输入,先输出这个组的编号(第n组就是输出“Case n:”);然后输出这组用户请求中循环节最多的子串。如果一个用户请求中有两个循环节数相同的子串,请选择那个字典序最小的。
样例输入
ilovejohnsonjohnsonverymuch
duckduckgo
aaabbbcccisagoodcompany
#


样例输出
Case 1: johnsonjohnson
Case 2: duckduck
Case 3: aaa


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 100100
#define BIG(a,b) ((a)<(b)?(b):(a))
#define SML(a,b) ((a)>(b)?(b):(a))
char s[MAX];
int sag[5][MAX];

int len, *rk, *sa, *h, *hh, *jl;
int ans[3], rmq[17][MAX], rmq2[17][MAX];

int cmp(int i, int j, int k) {
if(rk[i] - rk[j]) return rk[i] - rk[j];
i = (i + k >= len ? 0 : rk[i + k]);
j = (j + k >= len ? 0 : rk[j + k]);
return i - j;
}

void suffixArray(char *s) {
int k, i, j, l, num, *nr, *ns, *rdx, *p;
rk = sag[0], sa = sag[1], nr = sag[2], ns = sag[3], rdx = sag[4];
len = strlen(s) + 1;
memset(rk, 0, sizeof(sag[0]));
for(i = 0; i < len; ++i) ++rk[s[i]];
for(i = 1; i < 256; ++i) rk[i] += rk[i - 1];
for(i = 0; i < len; ++i) sa[--rk[s[i]]] = i;
for(i = 1, j = rk[sa[0]] = 0; i < len; ++i) {
if(s[sa[i]] != s[sa[i - 1]]) ++j;
rk[sa[i]] = j;
}
for(k = 1; k < len; k <<= 1) {
memset(rdx, -1, sizeof(sag[0]));
for(i = len - k; i < len; ++i) {
nr[i] = rdx[rk[i]];
rdx[rk[i]] = i;
}
for(i = 0; i < len; ++i) {
if(sa[i] - k < 0) continue;
num = rk[sa[i] - k];
nr[sa[i] - k] = rdx[num];
rdx[num] = sa[i] - k;
}
for(i = j, l = len; i >= 0; --i) {
for(num = rdx[i]; num != -1; num = nr[num]) ns[--l] = num;
}
for(i = 1, j = nr[ns[0]] = 0; i < len; ++i) {
if(cmp(ns[i], ns[i - 1], k)) ++j;
nr[ns[i]] = j;
}
p = rk; rk = nr; nr = p;
p = sa; sa = ns; ns = p;
}

h = nr; hh = ns;

for(i = 0; i < len; ++i) {
rk[sa[i]] = i;
}

h[len - 1] = 0;
for(int i = 0, j = 0; i < len - 1; ++i) {
while(s[sa[rk[i] - 1] + j] == s[i + j]) ++j;
h[i] = j;
hh[rk[i]] = j;
if(j > 0) --j;
}
}

void init() {
int i, j, l;
for(j = 0; j < len; ++j) {
rmq[0][j] = hh[j];
rmq2[0][j] = rk[j];
}
for(i = 2, l = 1; i < len; i <<= 1, ++l) {
for(j = 0; j + i / 2 < len; ++j) {
if(rmq[l - 1][j + i / 2] < rmq[l - 1][j]) rmq[l][j] = rmq[l - 1][j + i / 2];
else rmq[l][j] = rmq[l - 1][j];
if(rmq2[l - 1][j + i / 2] < rmq2[l - 1][j]) rmq2[l][j] = rmq2[l - 1][j + i / 2];
else rmq2[l][j] = rmq2[l - 1][j];
}
}
}

int find(int a, int b, int xx[17][MAX] = rmq) {
if(a > b) a ^= b ^= a ^= b;
if(a == b) return xx[0][a];
int i, j, l;
i = 1, j = 0, l = b - a;
while(i * 2 < l + 1) {
i <<= 1;
++j;
}
return SML(xx[j][a], xx[j][b - i + 1]);
}

int bf(int a, int b, int c) {
int d = b - a;
int beg = a - d + 1, end = a, mid;
if(beg < 0) beg = 0;
while(beg < end) {
mid = (beg + end) / 2;
if(mid + find(SML(rk[mid], rk[mid + d]) + 1, BIG(rk[mid], rk[mid + d])) == a + c) end = mid;
else beg = mid + 1;
}
return end;
}

void solve() {
int i, j, l, a, b, c;
suffixArray(s);
init();
ans[0] = 1;
ans[1] = sa[1];
ans[2] = sa[1] + 1;

for(i = 1; i < len / 2 + 1; ++i) {
for(j = 0; j < len - ans[0] * i; j += i) {
b = SML(rk[j], rk[j + i]);
c = BIG(rk[j], rk[j + i]);
a = find(b + 1, c);
l = bf(j, j + i, a);
b = SML(rk[l], rk[l + i]);
c = BIG(rk[l], rk[l + i]);
a = find(b + 1, c);
if(a >= i) {
if(a % i != 0) l = sa[find(l, l + a % i, rmq2)];
a -= (a % i);
if(a / i + 1 > ans[0] || (a / i + 1 == ans[0] && rk[ans[1]] > rk[l])) {
ans[0] = a / i + 1;
ans[1] = l;
ans[2] = l + a + i;
}
}
}
}
s[ans[2]] = '\0';
puts(&s[ans[1]]);

}

int main() {
int tt = 1;
while(gets(s)) {
if(s[0] == '#') break;
printf("Case %d: ", tt++);
solve();
}
return 0;
}


以下代码也可以解决问题,但是百度的OJ系统认定超时。

#include<stdio.h>
#include<string.h>
char str[100005],ans[100005],tmp[100005];
int next[100005];

inline void copy(char* dest,char* src,int len){
dest[len]=0;
while (len--) dest[len]=src[len];
}

int main()
{
int sz,st,len,end,n=1,i,j,maxsz;
bool noDecrs;
while (scanf ("%s",str)){
if (str[0]=='#')
return 0;
memset(ans,0,100005);
maxsz=0;
len=strlen(str);
noDecrs=true;
for (sz=len;sz>0 && noDecrs;sz--)
for (st=0;st+sz<=len;st++){
end=st+sz;
j=-1; next[st]=-1;
for (i=1;i<sz;i++){
while (j>=0 && str[j+st+1]!=str[i+st])
j=next[j];
if (str[j+st+1]==str[i+st])
j++;
next[i]=j;
}
i=sz-next[sz-1]-1;
if (sz%i) i=1;
else i=sz/i;
if (i==sz) noDecrs=false;
if (i>=maxsz && i*maxsz!=1){
if (i>maxsz){
copy(ans,str+st,sz);
maxsz=i;
}
else {
copy(tmp,str+st,sz);
if (strcmp(tmp,ans)<0)
copy(ans,tmp,sz);
}
}
}
printf("Case %d: %s\n",n,ans);
n++;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: