代码模板 拓展kmp (模板题 uoj #5 noi2014 动物园)

题目链接:[http://uoj.ac/problem/5]
题解:直接求出next数组,发现对一段结尾的子串有+1贡献。前缀和差分统计即可。

exkmp代码
学习的这位大佬

//uoj 5 noi 2014
//exkmp 用处。求一个串的所有后缀与另一个串的最长公共前缀。
//本题只用了next数组的性质
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define inf 1e8

typedef long long ll;
const ll mod = 1e9 + 7;
ll ans;
int n,T;
char s[maxn],t[maxn];
int next_[maxn]; //表示一个串与每个后缀的最长公共前缀
int ex[maxn]; //表示一个串与模板串所有后缀的最长公共前缀的长度
int sum[maxn];

void clear(){
    rep(i,0,n) sum[i] = next_[i] = 0;
}
void getnext_(char *s){
    int len = strlen(s),po = 1,i = 0,j; //po表示当前匹配前缀最长的后缀的起点
    next_[0] = len;
    //计算next_[1]
    while ( s[i] == s[i + 1] && i + 1 < len ) i++;
    next_[1] = i;
    for (i = 2;i < len ; i++){
        if ( next_[i - po] + i < next_[po] + po ) next_[i] = next_[i - po];//长度未超出匹配,可以直接得到next_[i]的值
        else{ //next_的长度超出当前匹配,要继续匹配才能得到next_[i]的值
            j = max(0,next_[po] + po - i); //从当前最远位置开始,如果i超出当前最远则从0开始
            while ( i + j < len && s[j] == s[j + i] ) j++; //往后继续匹配
            next_[i] = j;
            po = i; //更新最远位置
        }
    }
//  rep(i,0,len - 1) cout<<next_[i]<<" ";
//  cout<<endl;
}
void exkmp(char *s,char *t){
    int i = 0,j,po = 0,l1 = strlen(s),l2 = strlen(t);
    getnext_(t);//计算子串的next_数组
    while ( s[i] == t[i] && i < min(l1,l2) ) i++;
    ex[0] = i;  //计算ex[0]
    for(i = 1 ; i < l1 ; i++){
        if ( next_[i - po] + i < ex[po] + po ) ex[i] = next_[i - po];//第一种情况,直接可以得到ex[i]的值
        else{//第二种情况,要继续匹配才能得到ex[i]的值
            j = max(0,ex[po] + po - i);//如果i>ex[po]+po则要从头开始匹配从当前最远位置开始
            while ( i + j < l1 && j < l2 && s[i + j] == t[j] ) j++;
            ex[i] = j;
            po = i;//更新po的位置
        }
    }
}
int main(){
    freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while ( T-- ){
        clear();
        scanf("%s",s);
        n = strlen(s);
        getnext_(s);
        rep(i,0,n - 1){
            int len = min(next_[i],(int)i);
            sum[i]++ , sum[i + len]--;
        }
        int cur = 0; ans = 1;
        rep(i,0,n - 1){
            cur += sum[i];
            ans = ans * (cur + 1) % mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/81485937