zoukankan      html  css  js  c++  java
  • 【2012百度之星/资格赛】H:用户请求中的品牌

    时间限制: 
    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;    
    }
    


  • 相关阅读:
    .Net转Java自学之路—SpringMVC框架篇九(拦截器)
    .Net转Java自学之路—SpringMVC框架篇八(RESTful支持)
    移动端高清适配、布局开发解决方案
    Webpack+Gulp+React+ES6开发
    gulp使用gulp-file-include将header/footer引入页面
    git在window与linux的换行符问题
    文件(图片)上传组件
    ie8、9跨域上传文件(图片)
    移动端rem布局背景图片使用以及sprite雪碧图
    iOS/Android 浏览器(h5)及微信中唤起本地APP
  • 原文地址:https://www.cnblogs.com/ituff/p/2858537.html
Copyright © 2011-2022 走看看