zoukankan      html  css  js  c++  java
  • (HDU 5558) 2015ACM/ICPC亚洲区合肥站---Alice's Classified Message(后缀数组)

    题目链接

    http://acm.hdu.edu.cn/showproblem.php?pid=5558

    Problem Description
    Alice wants to send a classified message to Bob. She tries to encrypt the message with her original encryption method. The message is a string S, which consists of Nlowercase letters.

    S[ab] means a substring of S ranging from S[a] to S[b] (0ab<N). If the first i letters have been encrypted, Alice will try to find a magic string P. Assuming P has K letters, P is the longest string which satisfies P=S[T...T+K1] (0T<iT+KN) and P=S[ii+K1](i+KN). In other words, P is a substring of S, of which starting address is within [0...i1], and P is also a prefix of S[i...N1]. If P exists, Alice will append integer Kand T to ciphertext. If T is not unique, Alice would select the minimal one. And then i is incremented by K. If P does not exist, Alice will append -1 and the ASCII code of letter S[i] to ciphertext, and then increment i by 1.

    Obviously the first letter cannot be encrypted. That is to say, P does not exist when i=0. So the first integer of ciphertext must be -1, and the second integer is the ASCII code of S[0].

    When i=N, all letters are encrypted, and Alice gets the final ciphertext, which consists of many pairs of integers. Please help Alice to implement this method.
     
    Input
    The first line of input contains an integer T, which represents the number of test cases (T50). Each test case contains a line of string, which has no more than 100000 lowercase letters. It is guaranteed that the total length of the strings is not greater than 2×106.
     
    Output
    For each test case, output a single line consisting of “Case #X:” first. X is the test case number starting from 1. Output the ciphertext in the following lines. Each line contains two integers separated by a single space.
     
    Sample Input
    2
    aaaaaa
    aaaaabbbbbaaabbc
     
    Sample Output
    Case #1:
    -1 97
    5 0
    Case #2:
    -1 97
    4 0
    -1 98
    4 5
    5 2
    -1 99
     
    Source
     
    Recommend
    wange2014   |   We have carefully selected several similar problems for you:  5932 5931 5930 5929 5928 
     
    题意:输入一个只含有小写英文字母的字符串s[], 现在进行计算,对于当前位置i  在0~i-1 中找到j 使得后缀suffix[i] 和 suffix[j] 的公共前缀最长(设公共前缀长为k),输出长度和j,如果有多个j公共前缀长度一样,输出最小的j ,然后i=i+k  重复上述过程,直至i>=len;
     
    思路:先用后缀数组模板计算出名次数组和后缀数组 及最长公共前缀height[]数组 ,然后对于i  求出i的排名,然后根据i的排名,向比i大和小的排名找,取一个最大值;
     
    代码如下:
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <bitset>
    using namespace std;
    const int N=1e5+5;
    char s[N];
    int wa[N],wb[N],wv[N],wss[N];
    int rankk[N],height[N],sa[N];
    int cmp(int *r,int a,int b,int l){
       return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void da(char *r,int *sa,int n,int m)
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) wss[i]=0;
        for(i=0;i<n;i++) wss[x[i]=r[i]]++;
        for(i=1;i<m;i++) wss[i]+=wss[i-1];
        for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i;
        for(j=1,p=1;p<n;j*=2,m=p)
        {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) wss[i]=0;
            for(i=0;i<n;i++) wss[wv[i]]++;
            for(i=1;i<m;i++) wss[i]+=wss[i-1];
            for(i=n-1;i>=0;i--) sa[--wss[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        return ;
    }
    void calheight(char *r,int *sa,int n)
    {
        int i,j,k=0;
        for(i=1;i<=n;i++) rankk[sa[i]]=i;
        for(i=0;i<n;height[rankk[i++]]=k)
            for(k?k--:0,j=sa[rankk[i]-1];r[i+k]==r[j+k];k++);
        return ;
    }
    
    int main()
    {
        int T,Case=1;
        cin>>T;
        while(T--)
        {
            scanf("%s",s);
            int len=strlen(s);
            da(s,sa,len+1,130);
            calheight(s,sa,len);
            printf("Case #%d:
    ",Case++);
            int i=0;
            while(i<len)
           {
               int pos,k=0;
               int rk=rankk[i];
               int d=height[rk];
               for(int j=rk;j>=1&&height[j]!=0;j--)
               {
                   d=min(d,height[j]);
                   if(d<k) break;
                   if(sa[j-1]<i&&((d>k)||(d==k&&sa[j-1]<pos))) {
                        k=d; pos=sa[j-1];
                   }
               }
               if(rk<len){
                    d=height[rk+1];
                    for(int j=rk+1; j<=len&&height[j]!=0; j++)
                    {
                         d=min(d,height[j]);
                         if(d<k)  break;
                         if(sa[j]<i&&((d>k)||(d==k&&sa[j]<pos))) {
                            k=d; pos=sa[j];
                         }
                    }
               }
               if(k) printf("%d %d
    ",k,pos),i+=k;
               else  printf("%d %d
    ",-1,(int)s[i++]);
           }
        }
        return 0;
    }

    方法二:集合查找

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <bitset>
    using namespace std;
    const int N=1e5+5;
    char s[N];
    int wa[N],wb[N],wv[N],wss[N];
    int cmp(int *r,int a,int b,int l){
       return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void da(char *r,int *sa,int n,int m)
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) wss[i]=0;
        for(i=0;i<n;i++) wss[x[i]=r[i]]++;
        for(i=1;i<m;i++) wss[i]+=wss[i-1];
        for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i;
        for(j=1,p=1;p<n;j*=2,m=p)
        {
            for(p=0,i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) wss[i]=0;
            for(i=0;i<n;i++) wss[wv[i]]++;
            for(i=1;i<m;i++) wss[i]+=wss[i-1];
            for(i=n-1;i>=0;i--) sa[--wss[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        return ;
    }
    int rankk[N],height[N],sa[N],m[20][N];
    void calheight(char *r,int *sa,int n)
    {
        int i,j,k=0;
        for(int i=1;i<=n;i++) rankk[sa[i]]=i;
        for(i=0;i<n;height[rankk[i++]]=k)
            for(k?k--:0,j=sa[rankk[i]-1];r[i+k]==r[j+k];k++);
        return ;
    }
    set<int>se;
    set<int>:: iterator it1,it2;
    
    int main()
    {
        int T,Case=1;
        cin>>T;
        while(T--)
        {
            scanf("%s",s);
            int len=strlen(s);
            da(s,sa,len+1,130);
            calheight(s,sa,len);
            memset(m,0,sizeof(m));
            for(int i=2;i<=len;i++)
                m[1][i-1]=height[i];
            for(int i=2;i<=(int)(log(len)/log(2));i++)
            {
                for(int j=1;j+(1<<i)-1<=len;j++)
                m[i][j]=min(height[j+(1<<(i-1))],min(m[i-1][j],m[i-1][j+(1<<(i-1))]));
            }
            printf("Case #%d:
    ",Case++);
            int tot=0,minn=-999,maxn=9999999;
            se.clear();
            se.insert(minn);
            se.insert(maxn);
            while(tot<len)
            {
                int k=0,p;
                int pos=tot;
                it1=se.upper_bound(rankk[tot]);
                it2=it1;
                while(*it1!=maxn)
                {
                    int v=(int)(log(*it1-rankk[tot]+1)/log(2));
                    int f=min(m[v][rankk[tot]],m[v][*it1-(1<<v)+1]);
                    if(f<k||f==0) break;
                    if(f>k||(f==k&&sa[*it1]<p)){
                        k=f;
                        p=sa[*it1];
                    }
                    it1++;
                }
                it2--;
                while(*it2!=minn){
                    int v=(int)(log(rankk[tot]-*it2+1)/log(2));
                    int f=min(m[v][*it2],m[v][rankk[tot]-(1<<v)+1]);
                    if(f<k||f==0) break;
                    if(f>k||(f==k&&sa[*it2]<p)){
                        k=f;
                        p=sa[*it2];
                    }
                    it2--;
                }
                if(k==0) {
                    printf("%d %d
    ",-1,(int)s[tot]);
                    tot++;
                }
                else {
                    printf("%d %d
    ",k,p);
                    tot+=k;
                }
                for(;pos<tot;pos++)
                    se.insert(rankk[pos]);
            }
        }
        return 0;
    }
  • 相关阅读:
    D3D中的粒子系统(1)
    半角/全角的转换算法
    对Native API NtSystemDebugControl的分析
    教你快速下载fs2you.com网盘的文件
    养眼的编辑器配色
    Direct3D中的绘制(2)
    在服务里面弹出一个窗口到用户的桌面上[转]
    驱动级隐藏文件,注册表,进程
    GB2312转unicode程序
    Direct3D中的绘制(5)
  • 原文地址:https://www.cnblogs.com/chen9510/p/5956054.html
Copyright © 2011-2022 走看看