zoukankan      html  css  js  c++  java
  • 落谷P3041 [USACO12JAN]Video Game G

    题目链接


    多模式匹配问题,先建 AC 自动机。

    套路性的搞个 DP:

    • (f[i][j]) 表示前 (i) 个字符,当前在 (AC) 自动机上的节点是 (j) 能匹配到的最多分。
    • 初始化 (f[0][0] = 0),其余为负无穷
    • 答案 (max{f[K][i]})

    考虑一条边 (u Rightarrow v),加入后缀的贡献,即 (f[i][v] = max(f[i - 1][u] + val(v)))

    其中 (val(v)) 表示 (v) 这个点上出现的模式串个数,即其 fail 树的他到根的链上的是模式串末尾的个数。

    复杂度 (O(45NK))

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int S = 20, L = 305, M = 1005;
    
    int n, K, tr[L][3], fail[L];
    int cnt[L], q[L], idx, f[M][L];
    char s[S];
    
    void insert() {
    	int p = 0;
    	for (int i = 1; s[i]; i++) {
    		int ch = s[i] - 'A';
    		if (!tr[p][ch]) tr[p][ch] = ++idx;
    		p = tr[p][ch];
    	}
    	cnt[p]++;
    }
    
    void build() {
    	int hh = 0, tt = -1;
    	for (int i = 0; i < 3; i++)
    		if (tr[0][i]) q[++tt] = tr[0][i];
    	while (hh <= tt) {
    		int u = q[hh++];
    		for (int i = 0; i < 3; i++) {
    			int v = tr[u][i];
    			if (v) {
    				fail[v] = tr[fail[u]][i];
    				cnt[v] += cnt[fail[v]];
    				q[++tt] = v;
    			} else tr[u][i] = tr[fail[u]][i];
    		}
    	}
    }
    
    int main() {
    	memset(f, 0xcf, sizeof f);
    	scanf("%d%d", &n, &K);
    	for (int i = 1; i <= n; i++) {
    		scanf("%s", s + 1);
    		insert();
    	}
    	build();
    	f[0][0] = 0;
    	for (int i = 0; i < K; i++) {
    		for (int u = 0; u <= idx; u++) {
    			if (f[i][u] < 0) continue;
    			for (int j = 0; j < 3; j++) {
    				int v = tr[u][j];
    				f[i + 1][v] = max(f[i + 1][v], f[i][u] + cnt[v]);
    			}
    		}
    	}
    	int ans = 0;
    	for (int i = 0; i <= idx; i++) ans = max(ans, f[K][i]);
    	printf("%d
    ", ans);
    }
    
  • 相关阅读:
    第二阶段冲刺站立会议报告
    09软件工程读后感之三
    08软件工程读后感之二
    07软件工程读后感之一
    一个整数数组中最大字数组二
    返回一个二维数组最大联通子数组的和
    项目阶段总结
    大道至简阅读笔记之三
    大道至简阅读笔记二
    课堂设计
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12444723.html
Copyright © 2011-2022 走看看