标签:
| Time Limit: 5000MS | Memory Limit: 65536K | |
| Total Submissions: 8471 | Accepted: 2798 | 
Description
A substring of a string T is defined as:
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):
You are to give the value of |S| for specific A, B and K.
Input
The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.
1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.
Output
For each case, output an integer |S|.
Sample Input
2 aababaa abaabaa 1 xx xx 0
Sample Output
22 5
Source
POJ Monthly--2007.10.06, wintokk
题目大意:
就是可以匹配到的长度大于k的公共子串个数,即S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}.个数
例如第二组,长度为1时,第一个串取第一个x,第二个串可以去第一个或第二个,种类为2,第一个串取第二个一样,种类又是2,对于长度为2时,第一个串全取,第二个串全取,一种,总共有五种
思路:按题目的意思可以转换为求所有的i ,j,两个串后缀的最长公共前缀长度lcp(s1[i],s2[j])-k+1>0的和,暴力绝对超时,所以运用一个单调栈来求所有串和这个串的最长前缀
剩下的思路讲解来自http://m.blog.csdn.net/blog/u012866104/38725689
开始用比较习惯的写法,提交过了发现跑了900多,感觉有些慢,换了以前的写法又写了一遍稍微快一点点
ac代码1
Problem: 3415 User: kxh1995 Memory: 5064K Time: 938MS Language: C++ Result: Accepted
#include<stdio.h>       
#include<string.h>       
#include<algorithm>       
#include<iostream>        
using namespace std;      
char str[200010];    
int sa[200100],Rank[200100],rank2[200100],height[200010],c[200100],*x,*y;
int k,stack[200100][2];  
int n;  
void cmp(int n,int sz)  
{  
    int i;  
    memset(c,0,sizeof(c));  
    for(i=0;i<n;i++)  
        c[x[y[i]]]++;  
    for(i=1;i<sz;i++)  
        c[i]+=c[i-1];  
    for(i=n-1;i>=0;i--)  
        sa[--c[x[y[i]]]]=y[i];  
}  
void build_sa(char *s,int n,int sz)  
{  
    x=Rank,y=rank2;  
    int i,j;  
    for(i=0;i<n;i++)  
        x[i]=s[i],y[i]=i;  
    cmp(n,sz);  
    int len;  
    for(len=1;len<n;len<<=1)  
    {  
        int yid=0;  
        for(i=n-len;i<n;i++)  
        {  
            y[yid++]=i;  
        }  
        for(i=0;i<n;i++)  
            if(sa[i]>=len)  
                y[yid++]=sa[i]-len;  
            cmp(n,sz);  
        swap(x,y);  
        x[sa[0]]=yid=0;  
        for(i=1;i<n;i++)  
        {  
            if(y[sa[i-1]]==y[sa[i]]&&sa[i-1]+len<n&&sa[i]+len<n&&y[sa[i-1]+len]==y[sa[i]+len])  
                x[sa[i]]=yid;  
            else  
                x[sa[i]]=++yid;  
        }  
        sz=yid+1;  
        if(sz>=n)  
            break;  
    }  
    for(i=0;i<n;i++)  
        Rank[i]=x[i];  
}  
void getHeight(char *s,int n)  
{  
    int k=0;  
    for(int i=0;i<n;i++)  
    {  
        if(Rank[i]==0)  
            continue;  
        k=max(0,k-1);  
        int j=sa[Rank[i]-1];  
        while(s[i+k]==s[j+k])  
            k++;  
        height[Rank[i]]=k;  
    }  
} 
int main()
{
	while(scanf("%d",&k)!=EOF,k)
	{
		int i;
		scanf("%s",str);
		int len=strlen(str);
		str[len]=127;
		scanf("%s",str+len+1);
		int n=strlen(str);
		build_sa(str,n+1,128);
		getHeight(str,n);
		__int64 tot,top;
		tot=top=0;
		__int64 sum=0;
		for(i=1;i<=n;i++)
		{
			if(height[i]<k)
				top=tot=0;
			else
			{
				int cnt=0;
				if(sa[i-1]<len)
				{
					cnt++;
					tot+=height[i]-k+1;
				}
				while(top>0&&height[i]<=stack[top-1][0])
				{
					top--;
					tot-=stack[top][1]*(stack[top][0]-height[i]);
					cnt+=stack[top][1];
				}
				stack[top][0]=height[i];
				stack[top++][1]=cnt;
				if(sa[i]>len)
					sum+=tot;
			}
		}
		tot=top=0;
		for(i=1;i<=n;i++)
		{
			if(height[i]<k)
				top=tot=0;
			else
			{
				int cnt=0;
				if(sa[i-1]>len)
				{
					cnt++;
					tot+=height[i]-k+1;
				}
				while(top>0&&height[i]<=stack[top-1][0])
				{
					top--;
					tot-=stack[top][1]*(stack[top][0]-height[i]);
					cnt+=stack[top][1];
				}
				stack[top][0]=height[i];
				stack[top++][1]=cnt;
				if(sa[i]<len)
					sum+=tot;
			}
		}
		printf("%I64d\n",sum);
	}
}Problem: 3415 User: kxh1995 Memory: 5856K Time: 797MS Language: C++ Result: Accepted
#include<stdio.h>       
#include<string.h>       
#include<algorithm>       
#include<iostream>      
#define min(a,b) (a>b?b:a)   
#define max(a,b) (a>b?a:b)    
using namespace std;      
char str[200010];    
int sa[200100],t1[200200],t2[200200],c[200200];  
int rank[200200],height[200200]; 
int k,stack[200100][2];  
int n;  
void build_sa(char s[],int n,int m)  
{  
    int i,j,p,*x=t1,*y=t2;  
    for(i=0;i<m;i++)  
        c[i]=0;  
    for(i=0;i<n;i++)  
        c[x[i]=s[i]]++;  
    for(i=1;i<m;i++)  
        c[i]+=c[i-1];  
    for(i=n-1;i>=0;i--)  
        sa[--c[x[i]]]=i;  
    for(j=1;j<=n;j<<=1)  
    {  
        p=0;  
        for(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++)  
            c[i]=0;  
        for(i=0;i<n;i++)  
            c[x[y[i]]]++;  
        for(i=1;i<m;i++)  
            c[i]+=c[i-1];  
        for(i=n-1;i>=0;i--)  
            sa[--c[x[y[i]]]]=y[i];  
        swap(x,y);  
        p=1;  
        x[sa[0]]=0;  
        for(i=1;i<n;i++)  
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;  
        if(p>=n)  
            break;  
        m=p;  
    }  
}  
void getHeight(char *s,int n)  
{  
    int i,j,k=0;  
    for(i=0;i<=n;i++)  
        rank[sa[i]]=i;  
    for(i=0;i<n;i++)  
    {  
        if(k)  
            k--;  
        j=sa[rank[i]-1];  
        while(s[i+k]==s[j+k])  
            k++;  
        height[rank[i]]=k;  
    }  
}
int main()
{
	while(scanf("%d",&k)!=EOF,k)
	{
		int i;
		scanf("%s",str);
		int len=strlen(str);
		str[len]=127;
		scanf("%s",str+len+1);
		int n=strlen(str);
		build_sa(str,n+1,128);
		getHeight(str,n);
		__int64 tot,top;
		tot=top=0;
		__int64 sum=0;
		for(i=1;i<=n;i++)
		{
			if(height[i]<k)
				top=tot=0;
			else
			{
				int cnt=0;
				if(sa[i-1]<len)
				{
					cnt++;
					tot+=height[i]-k+1;
				}
				while(top>0&&height[i]<=stack[top-1][0])
				{
					top--;
					tot-=stack[top][1]*(stack[top][0]-height[i]);
					cnt+=stack[top][1];
				}
				stack[top][0]=height[i];
				stack[top++][1]=cnt;
				if(sa[i]>len)
					sum+=tot;
			}
		}
		tot=top=0;
		for(i=1;i<=n;i++)
		{
			if(height[i]<k)
				top=tot=0;
			else
			{
				int cnt=0;
				if(sa[i-1]>len)
				{
					cnt++;
					tot+=height[i]-k+1;
				}
				while(top>0&&height[i]<=stack[top-1][0])
				{
					top--;
					tot-=stack[top][1]*(stack[top][0]-height[i]);
					cnt+=stack[top][1];
				}
				stack[top][0]=height[i];
				stack[top++][1]=cnt;
				if(sa[i]<len)
					sum+=tot;
			}
		}
		printf("%I64d\n",sum);
	}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 题目3415 Common Substrings(后缀数组+栈,求可以匹配到的长度大于k的公共子串个数)
标签:
原文地址:http://blog.csdn.net/yu_ch_sh/article/details/47981377