• Match:Censored!(AC自动机+DP+高精度)(POJ 1625)


                

                      Censored!

      题目大意:给定一些字符,将这些字符组成一个固定长度的字符串,但是字符串不能包含一些禁词,问你有多少种组合方式。

      这是一道好题,既然出现了“一些”禁词,那么这题肯定和AC自动机有点关系了,对于这一题来说,因为我们需要的是求出在N^M种状态除去包含禁词的状态数,枚举肯定是不现实的了,我们唯一能做的只能是DP,但是怎么DP呢?只能是通过AC自动机来想了,由此我们来看一下trie树,我们知道trie树是可以表示不同字符串前后缀的转移关系的,但是这一题并不是要我们求出字串中是否有禁词,而是要我们求出除了禁词的其他组合方式,那么我们可不可以通过trie树直接看出来呢?答案是可以的,但是我们要改进一下。

      如果我们把trie树中的Next数组补齐,比如在ACGT中含有禁词ACC,C,我们可以构建如下图的一个trie树

                    

      

      我们可以看到这棵trie树补齐了一般trie树不存在的边,其实就是把不存在的对应k子节点指向当前节点的fail节点的k节点,这样我们就可以找到所有元素转移的状态关系了,得到了这个东西,那么我们就可以用DP来把状态转移全部搞出来了,组成一个m长度的单词,只要我们不从失败状态(禁词的结尾)转出或者转入就OK了。

      这样一开DP就很容易理解了,状态转移方程dp[i+1][转移状态]=dp[i][trie树上某个节点]+dp[i+1][转移状态](转移状态是指的是其他节点转移过来的情况),那么怎么标定非法情况呢?我们不仅要把单词结尾标记为非法状态,如果当前位置fail指针的指向的k位置也为单词结尾,那么当前位置的指向的k位置也必须标记为非法状态,因为我们不能从这个节点转出(也就意味着这个单词是包含着另一个单词的)。

      

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <functional>
      4 #define MAX 130
      5 
      6 using namespace std;
      7 
      8 static int sum_node, Hash_Table[MAX];
      9 static char str[200];
     10 
     11 struct node
     12 {
     13     int if_end,num;//注意end位置不仅是标记单词的结束,而且还表示了是否能状态转移
     14     node *fail, *Next[MAX];
     15 }Mem_Pool[MAX], *Trie_Node[MAX], *Queue[MAX * 2];
     16 struct BigInterget
     17 {
     18     int A[25];
     19     enum { MOD = 10000 };
     20     BigInterget()//构析函数用于初始化大数,A[0]表示大数的长度
     21     {    
     22         memset(A, 0, sizeof(A)); 
     23         A[0] = 1; 
     24     }
     25     void set(int x)//用于设定一个32位的整数
     26     { 
     27         memset(A, 0, sizeof(A));
     28         A[0] = 1; A[1] = x; 
     29     }
     30     void print(void)
     31     {
     32         printf("%d", A[A[0]]);
     33         for (int i = A[0] - 1; i > 0; i--)
     34         {
     35             if (A[i] == 0){ printf("0000"); continue; }
     36             for (int k = 10; k*A[i] < MOD; k *= 10)
     37                 printf("0");
     38             printf("%d", A[i]);
     39         }
     40         printf("
    ");
     41     }
     42     int& operator [] (int pos) { return A[pos]; }
     43     const int& operator [] (int pos) const { return A[pos]; }
     44 
     45     BigInterget operator + (const BigInterget &B)
     46     {
     47         BigInterget C;
     48         C[0] = max(A[0], B[0]);
     49         for (int i = 1; i <= C[0]; i++)
     50             C[i] += A[i] + B[i], C[i + 1] += C[i] / MOD, C[i] %= MOD;
     51         if (C[C[0] + 1] > 0)C[0]++;//进位
     52         return C;
     53     }
     54 };
     55 static BigInterget dp[52][MAX];
     56 
     57 struct node *create_new_node(void);
     58 void put_letter_to_hash(const int);
     59 void Insert(struct node *);
     60 void build_ac_automation(struct node *);
     61 
     62 int main(void)
     63 {
     64     int Word_Length, Forbidden_Word_Sum, Letter_Type_Sum;
     65     while (~scanf("%d%d%d", &Letter_Type_Sum, &Word_Length, &Forbidden_Word_Sum))
     66     {
     67         sum_node = 0;
     68         memset(Hash_Table, 0, sizeof(Hash_Table));
     69         node *root = create_new_node();
     70         put_letter_to_hash(Letter_Type_Sum);
     71 
     72         for (int i = 0; i < Forbidden_Word_Sum; i++)
     73             Insert(root);
     74         build_ac_automation(root);
     75         
     76         for (int i = 0; i <= Word_Length; i++)
     77             for (int j = 0; j < sum_node; j++)
     78                 dp[i][j] = BigInterget();
     79         dp[0][0].set(1);
     80 
     81         for (int i = 0; i < Word_Length; i++)
     82             for (int j = 0; j < sum_node; j++)
     83             {
     84                 if (Mem_Pool[j].if_end)//不能从非法状态中转入
     85                     continue;
     86                 for (int k = 0; k < Letter_Type_Sum; k++)
     87                 {
     88                     if (Mem_Pool[j].Next[k]->if_end)//不能从非法状态中转出
     89                         continue;
     90                     int id = Mem_Pool[j].Next[k]->num;
     91                     dp[i + 1][id] = dp[i][j] + dp[i + 1][id];
     92                 }
     93             }
     94         BigInterget ans = BigInterget();
     95         for (int i = 0; i < sum_node; i++)
     96             ans = ans + dp[Word_Length][i];
     97         ans.print();
     98     }
     99     return EXIT_SUCCESS;
    100 }
    101 
    102 struct node *create_new_node(void)
    103 {
    104     node *tmp = &Mem_Pool[sum_node];
    105     tmp->fail = NULL;
    106     tmp->if_end = 0;
    107     tmp->num = sum_node++;
    108     memset(tmp->Next, NULL, sizeof(struct node*)*MAX);
    109     return tmp;
    110 }
    111 
    112 void put_letter_to_hash(const int Letter_Type_Sum)
    113 {
    114     getchar();//去掉回车换行
    115     gets(str);
    116 
    117     for (int i = 0; i < Letter_Type_Sum; i++)
    118         Hash_Table[str[i]] = i;
    119 }
    120 
    121 void Insert(struct node *root)
    122 {
    123     gets(str);
    124     struct node *tmp_ptr = root;
    125 
    126     for (int i = 0; str[i] != ''; i++)
    127     {
    128         int id = Hash_Table[str[i]];
    129         if (tmp_ptr->Next[id] == NULL)
    130             tmp_ptr->Next[id] = create_new_node();
    131         tmp_ptr = tmp_ptr->Next[id];
    132     }
    133     tmp_ptr->if_end = 1;
    134 }
    135 
    136 void build_ac_automation(struct node *root)
    137 {
    138     int head = 0, tail = 0;
    139     node *out = NULL;
    140     root->fail = NULL;
    141     Queue[tail++] = root;
    142     
    143     while (head != tail)
    144     {
    145         out = Queue[head++];
    146         for (int i = 0; i < MAX; i++)
    147             if (out->Next[i] != NULL)
    148             {
    149                 if (out == root)
    150                     out->Next[i]->fail = root;
    151                 else
    152                 {
    153                     out->Next[i]->fail = out->fail->Next[i];
    154                     //如果还找到在其他地方找到和他一样的元素,那么我们就把失败指针指向这个元素,同时要设定合法状态
    155                     out->Next[i]->if_end = out->fail->Next[i]->if_end ? 1 : out->Next[i]->if_end;
    156                 }
    157                 Queue[tail++] = out->Next[i];
    158             }
    159             else
    160             {
    161                 if (out == root) out->Next[i] = root;
    162                 else out->Next[i] = out->fail->Next[i];
    163             }
    164     }
    165 }

      另外这个题要用到大数加法,在网上找了个很好的模板,以后就用这个了

      

      参考:http://blog.csdn.net/AndyTeen/article/details/45668121

         http://blog.csdn.net/scut_pein/article/details/22204681

         http://www.cnblogs.com/laiba2004/p/4004417.html

  • 相关阅读:
    [Reinforcement Learning] Cross-entropy Method
    [Deep Learning] 正则化
    [Deep Learning] 常用的Active functions & Optimizers
    [Machine Learning] 浅谈LR算法的Cost Function
    [Deep Learning] 深度学习中消失的梯度
    [Machine Learning] logistic函数和softmax函数
    [Deep Learning] 神经网络基础
    [Machine Learning] Active Learning
    [Machine Learning & Algorithm]CAML机器学习系列2:深入浅出ML之Entropy-Based家族
    [Machine Learning & Algorithm]CAML机器学习系列1:深入浅出ML之Regression家族
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5189842.html
Copyright © 2020-2023  润新知