(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:\n",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\n",k,pos),i+=k;
           else  printf("%d %d\n",-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:\n",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\n",-1,(int)s[tot]);
                tot++;
            }
            else {
                printf("%d %d\n",k,p);
                tot+=k;
            }
            for(;pos<tot;pos++)
                se.insert(rankk[pos]);
        }
    }
    return 0;
}

 

posted @ 2016-10-13 12:33  茶飘香~  阅读(3008)  评论(0编辑  收藏  举报