URAL_1158

    一开始实在想不出什么思路,后来看了《Trie图的构建、活用与改进》之后终于理解了所谓的AC自动机dp,如果你也和我一样看不懂别人的解题报告的话,不妨看看这篇文章,一定会有所收获。

    其实,如果我们把每个字符当作一个节点,然后把生成字符串的过程看作是在节点间行走的话,那么可以想象,如果0时刻从根节点出发开始行走的话,那么当前的合法字符串的数量,应该等于该时刻到达每个节点的可走路径条数的总和,因为一条路径对应的就是一个字符串。

    但是有一点很棘手,就是怎么才能控制自己走过的路径一定不含非法的字符串呢?trie图为我们提供了这个方便。如果我们把“行走”的过程看成在trie图上行走的话,那么只要经过的路径上不含有那篇文章所谓的“危险节点”即可,因为如果路过“危险节点”,就说明一定走出了非法字符串。

    此外,我的java代码在ZOJ同样的题目交也可以AC,但是在POJ上交不知道为什么会RE,如果路过的各位兄台谁知道其中的缘由的话,还望能告诉小弟,小弟不胜感激O(∩_∩)O~

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
public static int MAXD = 1010, MAXM = 60, Q = 1000;
public static int N, M, S, e;
public static int[] safe = new int[MAXD], q = new int[MAXD], P = new int[MAXD];
public static int[][] next = new int[MAXD][MAXM];
public static char[] alp, word;
public static BigInteger[][] f = new BigInteger[MAXM][MAXD];
public static Scanner cin = new Scanner(System.in);
public static void main(String[] args){
while(cin.hasNextInt())
{
N = cin.nextInt();
M = cin.nextInt();
S = cin.nextInt();
alp = cin.next().toCharArray();
init();
solve();
}
}
public static void add(int cur, int k)
{
++ e;
safe[e] = 0;
Arrays.fill(next[e], 0);
next[cur][k] = e;
}
public static void init()
{
int i, j, k, cur;
e = 0;
Arrays.fill(next[e], 0);
for(i = 0; i < S; i ++)
{
word = cin.next().toCharArray();
for(j = 0; j < word.length; j ++)
for(k = 0; k < N; k ++)
{
if(alp[k] == word[j])
word[j] = (char) (k);
}
cur = 0;
for(j = 0; j < word.length; j ++)
{
k = (int)word[j];
if(next[cur][k] == 0)
add(cur, k);
cur = next[cur][k];
}
safe[cur] = -1;
}
}
public static void solve()
{
int i, j, k, front, rear, cur;
for(i = 0; i < N; i ++)
if(next[0][i] == 0)
add(0, i);
front = rear = 0;
q[rear ++] = 0;
safe[0] = 1;
P[0] = 0;
while(front < rear)
{
cur = q[front ++];
if(safe[cur] == -1)
continue;
for(i = 0; i < N; i ++)
{
j = next[cur][i];
if(j != 0)
{
q[rear ++] = j;
if(cur == 0)
P[j] = 0;
else
{
for(k = P[cur]; k != 0; k = P[k])
if(next[k][i] != 0)
break;
P[j] = next[k][i];
}
if(safe[j] == 0)
safe[j] = safe[P[j]];
}
else
{
for(k = P[cur]; k != 0; k = P[k])
if(next[k][i] != 0)
break;
next[cur][i] = next[k][i];
}
}
}

front = rear = 0;
for(i = 0; i <= M; i ++)
Arrays.fill(f[i], new BigInteger("0"));
f[0][0] = new BigInteger("1");
for(i = 0; i < M; i ++)
for(j = 0; j <= e; j ++)
{
if(safe[j] == -1)
continue;
for(k = 0; k < N; k ++)
{
cur = next[j][k];
if(safe[cur] != -1)
f[i + 1][cur] = f[i + 1][cur].add(f[i][j]);
}
}
BigInteger ans = new BigInteger("0");
for(i = 1; i <= e; i ++)
ans = ans.add(f[M][i]);
System.out.println(ans);
}
}


posted on 2012-01-27 21:18  Staginner  阅读(470)  评论(0编辑  收藏  举报