zoukankan      html  css  js  c++  java
  • URAL 1158 Censored!

    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);
    }
    }


  • 相关阅读:
    [Flash开发笔记] ActionScript 生成伪 Guid
    [Flash开发笔记] 如何在as2.0中使用自定义类事件
    vs2005 智能感知不正常的解决办法
    [Flash开发笔记] 自定义ActionScript中的trim函数,取回车函数,字节换算函数
    爱你不容易——ExternalInterface
    软件测试中开发团队和测试团队的职责
    [Flash开发笔记] 正确理解MovieClipLoader的onLoadComplete事件
    ActionScript 中的字符串替换函数
    “hello world”PHP
    使用"类型文件"(typed File),创建自己的"数据库"
  • 原文地址:https://www.cnblogs.com/staginner/p/2330214.html
Copyright © 2011-2022 走看看