codeforces 1163D(AC自动机dp)

题意:给定一个文本串,两个模式串,将文本串的*替换为26个 字母,使得第一个模式串出现的次数减去第二个模式串出现的次数的差值最大。

思路:fail树的应用

          我们对两个模式串建立AC自动机,并计算出每个状态的权值。每个状态的权值定义为其fail树上一直到根节点的权值之和。原因为走到这个节点,就相当于到根节点路径上的的所有前缀都已经访问过了。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1005;
    const int N = 1005;
    const int inf = 0x3f3f3f3f;
    char str[maxn],s1[maxn],s2[maxn];
    int ch[N][26],tot,f[N],val[N],last[N],vis[N];
    void init(){
        tot = 0;
        memset( ch[0],0,sizeof(ch[0]) );
    }
    void Insert( char* str,int v ){
        int p = 0;int n = strlen(str);
        for( int i = 0;i < n;i++ ){
            int c= str[i]-'a';
            if( !ch[p][c] ){
                ch[p][c] = ++tot;val[tot] = 0;last[tot] = 0;f[tot] = 0;
                memset( ch[tot],0,sizeof(ch[tot]) );
            }
            p = ch[p][c];
        }
        val[p] += v;
    }
    queue<int> que,Q;
    void getfail(){
        for( int i = 0;i < 26;i++ ) {
            if( ch[0][i] ) {
                que.push( ch[0][i] );
                Q.push( ch[0][i] );
            }
        }
        while(que.size()){
            int x= que.front();
            que.pop();
            for( int c = 0;c < 26;c++ ){;
                if(!ch[x][c]){
                    ch[x][c] = ch[f[x]][c];
                    continue;
                }
                f[ch[x][c]] = ch[f[x]][c];
                last[ch[x][c]] = val[f[ch[x][x]]] ? f[ch[x][c]] : last[f[ch[x][c]]];
                que.push( ch[x][c] );Q.push( ch[x][c] );
            }
        }
    }
    int dp[maxn][maxn],len;
    int dfs( int x,int p ){
        if( dp[x][p] != -inf ) return dp[x][p];
        if( p == len ){
            return val[x];
        }
        if( str[p] == '*' ){
            int mx = -inf;
            for( int c = 0;c < 26;c++ ){
                mx = max( mx,dfs( ch[x][c],p+1 ) );
            }
            return dp[x][p] = val[x] + mx;
        }else{
            int res = dfs( ch[x][ str[p]-'a' ],p+1 );;
            return dp[x][p] = val[x] + res;
        }
    }
    int main(){
        scanf("%s%s%s",str,s1,s2);
        init();
        Insert(s1,1);Insert(s2,-1);
        getfail();
        while(Q.size()){
            int x = Q.front();
            Q.pop();
            val[x] += val[f[x]];
        }
        len = strlen(str);
        for( int i = 0;i <= tot;i++ ){
            for( int j = 0;j <= len;j++ ){
                dp[i][j] = -inf;
            }
        }
        int ans = dfs( 0,0 );
        printf("%d\n",ans);
        return 0;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值