POJ 3415 不小於k的公共子串的個數

Common Substrings
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 9248   Accepted: 3071

Description

A substring of a string T is defined as:

T(ik)=TiTi+1...Ti+k-1, 1≤ii+k-1≤|T|.

Given two strings AB and one integer K, we define S, a set of triples (ijk):

S = {(ijk) | kKA(ik)=B(jk)}.

You are to give the value of |S| for specific AB 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 byK=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|.



/*
POJ 3415 不小於k的公共子串的個數(思路)

給你兩個子串求長度不小於k的公共子串的個數

因爲每次枚舉一個子串就要和前面所有另一個串的所有已經出現情況取一個最小值
如果每次都把所有的掃描一遍的話很浪費時間,而且是與前面的所有取min,所有用棧保存的話
棧頂的肯定是最大值,所以棧內元素就成單調增的了。  每次只需要更新比當前值大的情況就好了

從頭到尾枚舉height,如果當前是屬於A串,則加上前面所有屬於B串的height-k+1.對於B串同理.
兩個串之間的公共前綴是它們之間所有的最小值,所以用棧維護一下,保證棧裏是單調遞增的,
這樣對於新增的串只需要處理其中height大於它的一部分即可

hhh-2016-03-15 23:25:42
*/
#include <algorithm>
#include <cmath>
#include <queue>
#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
#include <vector>
#include <functional>
#define lson (i<<1)
#define rson ((i<<1)|1)
using namespace std;
typedef long long ll;
const int maxn = 200050;

int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b] &&r[l+a] == r[l+b];
}

void get_sa(int str[],int sa[],int Rank[],int height[],int n,int m)
{
    n++;
    int p,*x=t1,*y=t2;
    for(int i = 0; i < m; i++) c[i] = 0;
    for(int i = 0; i < n; i++) c[x[i] = str[i]]++;
    for(int i = 1; i < m; i++) c[i] += c[i-1];
    for(int i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
    for(int j = 1; j <= n; j <<= 1)
    {
        p = 0;
        for(int i = n-j; i < n; i++) y[p++] = i;
        for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
        for(int i = 0; i < m; i++) c[i] = 0;
        for(int i = 0; i < n; i++) c[x[y[i]]]++ ;
        for(int i = 1; i < m; i++) c[i] += c[i-1];
        for(int i = n-1; i >= 0; i--)  sa[--c[x[y[i]]]] = y[i];

        swap(x,y);
        p = 1;
        x[sa[0]] = 0;
        for(int i = 1; i < n; i++)
            x[sa[i]] = cmp(y,sa[i-1],sa[i],j)? p-1:p++;
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(int i = 0; i <= n; i++)
        Rank[sa[i]] = i;
    for(int i = 0; i < n; i++)
    {
        if(k) k--;
        int j = sa[Rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[Rank[i]] = k;
    }
}

int Rank[maxn];
int sa[maxn];
int str[maxn],mark[4],height[maxn];
char s1[maxn],s2[maxn];
ll num[4],ans[maxn];

ll solve(int len,int n,int k)
{
    int top = 0;
    ll sum = 0;
    num[1] = num[2] = 0;
    for(int i = 1; i <= n; i++)
    {
        if(height[i] < k)
            top = num[1] = num[2] = 0;
        else
        {
            for(int j = top; ans[j] > height[i]+1-k && j; j--)
            {
                num[mark[j]] += (height[i]-k+1-ans[j]);
                ans[j] = height[i]-k+1;
            }
            ans[++top] = height[i]-k+1;
            if(sa[i-1]<len) mark[top] = 1;
            if(sa[i-1]>len) mark[top] = 2;
            num[mark[top]] += height[i]-k+1;
            if(sa[i] < len) sum += num[2];
            if(sa[i] > len) sum += num[1];
        }
    }
    return sum;
}

int main()
{
    int k;
    while(scanf("%d",&k) != EOF && k)
    {
        scanf("%s",s1);
        scanf("%s",s2);
        int tot = 0;
        int len1 = strlen(s1);
        for(int i = 0; s1[i]!='\0'; i++)
            str[tot++] = s1[i];
        str[tot++] = 1;
        for(int i = 0; s2[i]!='\0'; i++)
            str[tot++] = s2[i];
        str[tot] = 0;
        get_sa(str,sa,Rank,height,tot,200);
//        for(int i = 2;i <= tot;i++)
//            printf("%d ",height[i]);
//        printf("\n");
        cout << solve(len1,tot,k) <<endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章