POJ 3729 Facer's string (后缀数组)

原题链接

Problem Description

Minifacer was very happy these days because he has learned the algorithm of KMP recently. Yet his elder brother, Hugefacer, thought that Minifacer needs a deeper understanding of this algorithm. Thus Hugefacer decided to play a game with his little brother to enhance his skills.

First, Hugefacer wrote down two strings S1 and S2. Then Minifacer tried to find a substring S3 of S1 which meets the following requirements: 1) S3 should have a length of k (which is a constant value); 2) S3 should also be the substring of S2. After several rounds, Hugefacer found that this game was too easy for his clever little brother, so he added another requirement: 3) the extended string of S3 should NOT be the substring of S2. Here the extended string of S3 is defined as S3 plus its succeed character in S1 (if S3 does not have a succeed character in S1, the extended string of S3 is S3 + ’ ’ which will never appear in S2). For example, let S1 be “ababc”, if we select the substring from the first character to the second character as S3 (so S3 equals “ab”), its extended string should be “aba”; if we select the substring from the third character to the fourth character as S3, its extended string should be “abc”; if we select the substring from the fourth character to the fifth character as S3, its extended string should be “bc”.

Since the difficult level of the game has been greatly increased after the third requirement was added, Minifacer was not able to win the game and he thought that maybe none of the substring would meet all the requirements. In order to prove that Minifacer was wrong, Hugefacer would like to write a program to compute number of substrings that meet the three demands (Note that two strings with same appearance but different positions in original string S1 should be count twice). Since Hugefacer do not like characters, he will use non-negative integers (range from 0 to 10000) instead.

Input

There are multiple test cases. Each case contains three lines: the first line contains three integers n, m and k where n represents the length of S1, m represents the length of S2 and k represents the length of substring; the second line contains string S1 and the third line contains string S2. Here 0 ≤ n, m ≤ 50000. Input ends with EOF.

Output

For each test case, output a number in a line stand for the total number of substrings that meet the three requirements.

Sample Input

5 5 2
1 2 1 2 3
1 2 3 4 5
5 5 3
1 2 1 2 3
1 2 3 4 5

Sample Output

2
1

题目大意

第一行输入n,m,k,代表第一个数列中有n个数,第二个数列中有m个数,k表示子序列的长度。现在要在第一个数列中找长度为k的子序列使得它同样是第二个数列的子序列,但是要保证这个子序列在第一个数列中的后一个数不能等于它在第二个数列中的后一个数。

解题思路

总体的思路就是求后缀数组然后对后缀进行分组。具体地来说,先将两个数列连接,中间用一个足够大的数隔开,然后求一次后缀数组,由于题目的特殊条件“ the extended string of S3 should NOT be the substring of S2.”,我们可以去用公共字串长度大于等于k的数量减去公共子串长度大于等于k+1的数量得到长度恰好等于k的数量。

AC代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<map>
#define ll long long
#define ull unsigned long long
#define rep(i,n) for(int i = 0;i < n; i++)
#define fil(a,b) memset((a),(b),sizeof(a))
#define cl(a) fil(a,0)
#define pb push_back
#define mp make_pair
#define ee 2.7182818
#define PI 3.141592653589793
#define inf 0x3f3f3f3f
#define fi first
#define se second
#define eps 1e-7
#define mod 1000000007ll
using namespace std;

const int size  = 123456,INF = 1<<30;
int rk[size],sa[size],height[size],w[size],wa[size],res[size];
void getSa (int len,int up) {
    int *k = rk,*id = height,*r = res, *cnt = wa;
    rep(i,up) cnt[i] = 0;
    rep(i,len) cnt[k[i] = w[i]]++;
    rep(i,up) cnt[i+1] += cnt[i];
    for(int i = len - 1; i >= 0; i--) {
        sa[--cnt[k[i]]] = i;
    }
    int d = 1,p = 0;
    while(p < len){
        for(int i = len - d; i < len; i++) id[p++] = i;
        rep(i,len)  if(sa[i] >= d) id[p++] = sa[i] - d;
        rep(i,len) r[i] = k[id[i]];
        rep(i,up) cnt[i] = 0;
        rep(i,len) cnt[r[i]]++;
        rep(i,up) cnt[i+1] += cnt[i];
        for(int i = len - 1; i >= 0; i--) {
            sa[--cnt[r[i]]] = id[i];
        } 
        swap(k,r);
        p = 0;
        k[sa[0]] = p++;
        rep(i,len-1) {
            if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]] == r[sa[i+1]]&& r[sa[i]+d] == r[sa[i+1]+d])
                k[sa[i+1]] = p - 1;
            else k[sa[i+1]] = p++;
        }
        if(p >= len) return ;
        d *= 2,up = p, p = 0;
    }
}
void getHeight(int len) {
    rep(i,len) rk[sa[i]] = i;
    height[0] =  0;
    for(int i = 0,p = 0; i < len - 1; i++) {
        int j = sa[rk[i]-1];
        while(i+p < len&& j+p < len&& w[i+p] == w[j+p]) {
            p++;
        }
        height[rk[i]] = p;
        p = max(0,p - 1);
    }
}
int getSuffix(int s[],int len) {
    int up = 0; 
    for(int i = 0; i < len; i++) {
        w[i] = s[i];
        up = max(up,w[i]);
    }
    w[len++] = 0;
    getSa(len,up+1);
    getHeight(len);
    return len;
}
int a[123456];
int n,m,k;
int cal(int k,int len)
{
    int le=0;
    int mo=0;
    int cnt=0;
    if(sa[1]<n) le++;
    else mo++;
    for(int i=2;i<=len;++i)
    {
        if(height[i]<k)
        {
            if(mo>0) cnt+=le;
            mo=0;
            le=0;
        }
        if(sa[i]<n) le++;
        else mo++;
    }
    return cnt;
}
int main(void)
{
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        for(int i=0;i<n;++i)
        {
            scanf("%d",&a[i]);
            a[i]++;
        }
        a[n]=20000;
        for(int i=0;i<m;++i)
        {
            scanf("%d",&a[n+i+1]);
            a[n+i+1]++;
        }
        a[n+m+1]=0;
        int useless=getSuffix(a,n+m+2);
        cout<<cal(k,useless-1)-cal(k+1,useless-1)<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值