HDU 6153 扩展KMP

题目链接

题意:

给定母串S和子串T,在母串中找子串的所有后缀匹配次数乘于其对应的出现次数,最终将结果加起来输出。

思路:

同时翻转母串S和子串T,这样子匹配后缀就变为匹配前缀。匹配前缀就可以使用扩展KMP,最终将Ex[i]*(Ex[i]+1)/2求和就是答案。

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
const int  mod = 1e9+7;

void Rev ( char *s )
{
    int len = strlen(s);
    for ( int i=0,j=len-1 ; i<j ; i++,j-- )
        swap ( s[i] , s[j] );
}

void GetNext ( char *s , int *Next )
{
    int c = 0,len = strlen(s);
    Next[0] = len;
    while( s[c]==s[c+1]&&c+1<len ) c++;
    Next[1] = c;
    int po = 1;
    for ( int i=2 ; i<len ; i++ )
    {
        if ( Next[i-po]+i<Next[po]+po )
            Next[i] = Next[i-po];
        else
        {
            int t = Next[po]+po-i;
            if ( t<0 ) t = 0;
            while( i+t<len&&s[t]==s[i+t] ) t++;
            Next[i] = t;
            po = i;
        }
    }
}

void ExKmp ( char *s1 , char *s2 , int *Next , int *Ex )
{
    int c = 0,len = strlen(s1),l2 = strlen(s2);
    GetNext ( s2 , Next );
    while ( s1[c]==s2[c]&&c<len&&c<l2 ) c++;
    Ex[0] = c;
    int po = 0;
    for ( int i=1 ; i<len ; i++ )
    {
        if ( Next[i-po]+i<Ex[po]+po )
            Ex[i] = Next[i-po];
        else
        {
            int t = Ex[po]+po-i;
            if ( t<0 ) t = 0;
            while ( i+t<len&&t<l2&&s1[i+t]==s2[t] ) t++;
            Ex[i] = t;
            po = i;
        }
    }
}

char S[maxn],T[maxn];
int Next[maxn],Ex[maxn];

int main()
{
    int Cas; scanf ( "%d" , &Cas );
    while ( Cas-- )
    {
        scanf ( "%s%s" , S , T );
        Rev( S );
        Rev( T );
        long long ans = 0;
        ExKmp( S , T , Next , Ex );
        int len = strlen(S);
        for ( int i=0 ; i<len ; i++ )
            ans += ( long long )Ex[i]*(Ex[i]+1)/2;
        printf ( "%lld\n" , ans%mod );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/game_acm/article/details/81002571