POJ 3415 && HDU 4416

两道后缀数组的应用

POJ 3415求的是两个串的所有公共字串的个数

HDU 4416求的是两个串的所有不相同的公共字串的个数

POJ 3415

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MAXN 200100
typedef long long ll;
using namespace std;

char r[MAXN];
int sa[MAXN];
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int height[MAXN],rk[MAXN];

inline bool cmp(int *r,int a,int b,int len){
    return r[a]==r[b]&&r[a+len]==r[b+len];
}
void SA(int n,int m){
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++)
        ws[i]=0;
    for(i=0;i<n;i++)
        ws[x[i]=r[i]]++;
    for(i=1;i<m;i++)
        ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--)
        sa[--ws[x[i]]]=i;
    for(j=p=1;p<n;j<<=1,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<m;i++)
            ws[i]=0;
        for(i=0;i<n;i++)
            ws[wv[i]=x[y[i]]]++;
        for(i=1;i<m;i++)
            ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--)
            sa[--ws[wv[i]]]=y[i];
        for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}
void Height(int n){
    int i,j,k=0;
    for(i=0;i<=n;i++)    //这里sa[0]为‘\0’开始的子串
        rk[sa[i]]=i;
    for(i=0;i<n;height[rk[i++]]=k)
        for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
}

int la;

int init(){
    int i,j,len;
    memset(height,0,sizeof(height));
    scanf("%s",r);
    len=strlen(r);
    r[len]='$';
    la=len;
    scanf("%s",&r[len+1]);
	return strlen(r);
}

int k;

int count(int num){
	if(num<k) return 0;
	else return num-k+1;
}

void solve(int n){
	ll ans=0;
	ll suma=0,sumb=0;
	int sta[MAXN],top=0;
	sta[0]=0;
	ll ca[MAXN],cb[MAXN];
	ca[1]=cb[1]=0;
	for(int i=2;i<n;i++){
		if(sa[i]<=la){
			ca[i]=ca[i-1]+1;
			cb[i]=cb[i-1];
		}
		else{
			ca[i]=ca[i-1];
			cb[i]=cb[i-1]+1;
		}
	}
	for(int i=3;i<n;i++){
		if(sa[i-1]<=la) suma+=(ll)count(height[i]);
		else sumb+=(ll)count(height[i]);
		sta[++top]=i-1;
		while(top>=2 && height[sta[top]+1]<height[sta[top-1]+1]){
			suma-=(ll)(count(height[sta[top-1]+1])-count(height[sta[top]+1]))*(ca[sta[top-1]]-ca[sta[top-2]]);
			sumb-=(ll)(count(height[sta[top-1]+1])-count(height[sta[top]+1]))*(cb[sta[top-1]]-cb[sta[top-2]]);
			sta[top-1]=sta[top--];
		}
		if(sa[i]<=la) ans+=sumb;
		else ans+=suma;
	}
	printf("%lld\n",ans);
}

int main(){
    int n;
    while(scanf("%d",&k)){
		if(k==0) break;
        n=init();
        SA(n+1,130);
        Height(n);
        solve(n+1);
    }
}


HDU 4416


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 400100
char r[MAXN];
int hhh[MAXN];
int sa[MAXN];
int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN];
int height[MAXN],rank[MAXN];
int la,nn,t;
inline bool cmp(int *r,int a,int b,int len){
    return r[a]==r[b]&&r[a+len]==r[b+len];
}
void SA(int n,int m){
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++)
        ws[i]=0;
    for(i=0;i<n;i++)
        ws[x[i]=r[i]]++;
    for(i=1;i<m;i++)
        ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--)
        sa[--ws[x[i]]]=i;
    for(j=p=1;p<n;j<<=1,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<m;i++)
            ws[i]=0;
        for(i=0;i<n;i++)
            ws[wv[i]=x[y[i]]]++;
        for(i=1;i<m;i++)
            ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--)
            sa[--ws[wv[i]]]=y[i];
        for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}
void Height(int n){
    int i,j,k=0;
    for(i=1;i<=n;i++)
        rank[sa[i]]=i;
    for(i=0;i<n;height[rank[i++]]=k)
        for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
void init(){
    int i,j,nnn,n,tem;
    scanf("%d",&nnn);
    scanf("%s",r);
    la=strlen(r);
    r[la]='#';
    tem=la+1;
    for(i=1;i<=nnn;i++){
        scanf("%s",&r[tem]);
        n=strlen(&r[tem]);
        r[n+tem]='#';
        for(j=0;j<n;j++){
            hhh[j+tem]=tem+n;
            //printf("***%d := %d*****\n",tem+j,hhh[j+tem]);
        }
        tem+=n+1;
        hhh[tem-1]=0;
        //printf("***%d := %d*****\n",tem-1,hhh[tem-1]);
    }
    nn=tem;
}
void solve(int n){
    long long sum=0;
    int last=0,i,flag=0;
    //printf("%s\n",r);
    for(i=1;i<=n;i++){
        if(sa[i]<la){
            if(last==0){
                sum+=la-sa[i]-min(height[i],la-sa[i]);
                flag=sa[i]+min(height[i],la-sa[i])-1;
            }
            else if(last==1){
                sum+=la-sa[i]-min(height[i],la-sa[i]);
                flag=sa[i]+min(flag-sa[i-1]+1,min(height[i],la-sa[i]))-1;
                /*if(min(height[i],la-sa[i])==0)
                    flag=sa[i]-1;
                else if(flag>sa[i]+min(height[i],la-sa[i])-1)
                    flag=sa[i]+min(height[i],la-sa[i])-1;*/
            }
            last=1;
        }
        else{
            if(last==1)
                sum-=max(sa[i-1]+min(height[i],hhh[sa[i]]-sa[i])-1-flag,0);
            last=0;
        }
        //printf("****%d %d %d %lld***\n",sa[i],min(height[i],hhh[sa[i]]-sa[i]),flag,sum);
    }
    printf("Case %d: %I64d\n",t,sum);
}
int main(){
    int i,j,T,n;
    scanf("%d",&T);
    for(t=1;t<=T;t++){
        memset(height,0,sizeof(height));
        memset(r,'\0',sizeof(r));
        init();
        n=nn;
        SA(n+1,130);
        Height(n);
        solve(n);
    }
}



你可能感兴趣的:(POJ 3415 && HDU 4416)