【HDU】5129 Yong Zheng's Death【AC自动机+dp】

本文通过一道名为YongZheng’s Death的题目介绍了AC自动机的实现细节,包括节点结构定义、插入操作、失败指针建立及状态转移矩阵计算等核心步骤,并最终实现了字符串匹配的高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:Yong Zheng’s Death

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 300005 ;

int nxt[MAXN][26] ;
int word[MAXN] ;
int lens[MAXN] ;
int fail[MAXN] ;
int Q[MAXN] , head , tail ;
char s[MAXN] ;
int cur ;
int n ;
LL dp[33][MAXN] , ans ;

int newnode ( int i ) {
    clr ( nxt[cur] , 0 ) ;
    word[cur] = 0 ;
    lens[cur] = i + 1 ;
    dp[0][cur] = 0 ;
    return cur ++ ;
}

void insert ( char s[] , int n ) {
    int now = 0 ;
    for ( int i = 0 ; i < n ; ++ i ) {
        int x = s[i] - 'a' ;
        if ( nxt[now][x] == 0 ) nxt[now][x] = newnode ( i ) ;
        now = nxt[now][x] ;
    }
    word[now] = 1 ;
}

void build () {
    head = tail = 0 ;
    for ( int i = 0 ; i < 26 ; ++ i ) {
        if ( nxt[0][i] ) {
            Q[tail ++] = nxt[0][i] ;
            fail[nxt[0][i]] = 0 ;
        } else nxt[0][i] = 0 ;
    }
    while ( head != tail ) {
        int u = Q[head ++] ;
        if ( fail[u] ) ++ ans ;
        for ( int i = 0 ; i < 26 ; ++ i ) {
            if ( nxt[u][i] ) {
                fail[nxt[u][i]] = nxt[fail[u]][i] ;
                Q[tail ++] = nxt[u][i] ;
            } else {
                nxt[u][i] = nxt[fail[u]][i] ;
                if ( nxt[u][i] ) {
                    ++ ans ;
                    dp[0][nxt[u][i]] ++ ;
                }
            }
        }
    }
}

void solve () {
    cur = 0 ;
    newnode ( -1 ) ;
    int m = 0 ;
    for ( int i = 0 ; i < n ; ++ i ) {
        scanf ( "%s" , s ) ;
        int l = strlen ( s ) ;
        insert ( s , l ) ;
        m = max ( m , l ) ;
    }
    ans = 0 ;
    build () ;
    for ( int i = 1 ; i <= m ; ++ i ) {
        for ( int j = 0 ; j < cur ; ++ j ) {
            dp[i][j] = dp[i][j] = 0 ;
        }
        for ( int j = 1 ; j < cur ; ++ j ) if ( dp[i - 1][j] ) {
            for ( int k = 0 ; k < 26 ; ++ k ) {
                int t = nxt[j][k] ;
                if ( lens[t] <= i ) continue ;
                dp[i][t] += dp[i - 1][j] ;
            }
        }
        for ( int j = 1 ; j < cur ; ++ j ) {
            ans += dp[i][j] ;
        }
    }
    printf ( "%lld\n" , ans ) ;
}

int main () {
    while ( ~scanf ( "%d" , &n ) && n ) solve () ;
    return 0 ;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值