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位置也必须标记为非法状态,因为我们不能从这个节点转出(也就意味着这个单词是包含着另一个单词的)。

  

 #include <iostream>
#include <algorithm>
#include <functional>
#define MAX 130 using namespace std; static int sum_node, Hash_Table[MAX];
static char str[]; struct node
{
int if_end,num;//注意end位置不仅是标记单词的结束,而且还表示了是否能状态转移
node *fail, *Next[MAX];
}Mem_Pool[MAX], *Trie_Node[MAX], *Queue[MAX * ];
struct BigInterget
{
int A[];
enum { MOD = };
BigInterget()//构析函数用于初始化大数,A[0]表示大数的长度
{
memset(A, , sizeof(A));
A[] = ;
}
void set(int x)//用于设定一个32位的整数
{
memset(A, , sizeof(A));
A[] = ; A[] = x;
}
void print(void)
{
printf("%d", A[A[]]);
for (int i = A[] - ; i > ; i--)
{
if (A[i] == ){ printf(""); continue; }
for (int k = ; k*A[i] < MOD; k *= )
printf("");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int pos) { return A[pos]; }
const int& operator [] (int pos) const { return A[pos]; } BigInterget operator + (const BigInterget &B)
{
BigInterget C;
C[] = max(A[], B[]);
for (int i = ; i <= C[]; i++)
C[i] += A[i] + B[i], C[i + ] += C[i] / MOD, C[i] %= MOD;
if (C[C[] + ] > )C[]++;//进位
return C;
}
};
static BigInterget dp[][MAX]; struct node *create_new_node(void);
void put_letter_to_hash(const int);
void Insert(struct node *);
void build_ac_automation(struct node *); int main(void)
{
int Word_Length, Forbidden_Word_Sum, Letter_Type_Sum;
while (~scanf("%d%d%d", &Letter_Type_Sum, &Word_Length, &Forbidden_Word_Sum))
{
sum_node = ;
memset(Hash_Table, , sizeof(Hash_Table));
node *root = create_new_node();
put_letter_to_hash(Letter_Type_Sum); for (int i = ; i < Forbidden_Word_Sum; i++)
Insert(root);
build_ac_automation(root); for (int i = ; i <= Word_Length; i++)
for (int j = ; j < sum_node; j++)
dp[i][j] = BigInterget();
dp[][].set(); for (int i = ; i < Word_Length; i++)
for (int j = ; j < sum_node; j++)
{
if (Mem_Pool[j].if_end)//不能从非法状态中转入
continue;
for (int k = ; k < Letter_Type_Sum; k++)
{
if (Mem_Pool[j].Next[k]->if_end)//不能从非法状态中转出
continue;
int id = Mem_Pool[j].Next[k]->num;
dp[i + ][id] = dp[i][j] + dp[i + ][id];
}
}
BigInterget ans = BigInterget();
for (int i = ; i < sum_node; i++)
ans = ans + dp[Word_Length][i];
ans.print();
}
return EXIT_SUCCESS;
} struct node *create_new_node(void)
{
node *tmp = &Mem_Pool[sum_node];
tmp->fail = NULL;
tmp->if_end = ;
tmp->num = sum_node++;
memset(tmp->Next, NULL, sizeof(struct node*)*MAX);
return tmp;
} void put_letter_to_hash(const int Letter_Type_Sum)
{
getchar();//去掉回车换行
gets(str); for (int i = ; i < Letter_Type_Sum; i++)
Hash_Table[str[i]] = i;
} void Insert(struct node *root)
{
gets(str);
struct node *tmp_ptr = root; for (int i = ; str[i] != '\0'; i++)
{
int id = Hash_Table[str[i]];
if (tmp_ptr->Next[id] == NULL)
tmp_ptr->Next[id] = create_new_node();
tmp_ptr = tmp_ptr->Next[id];
}
tmp_ptr->if_end = ;
} void build_ac_automation(struct node *root)
{
int head = , tail = ;
node *out = NULL;
root->fail = NULL;
Queue[tail++] = root; while (head != tail)
{
out = Queue[head++];
for (int i = ; i < MAX; i++)
if (out->Next[i] != NULL)
{
if (out == root)
out->Next[i]->fail = root;
else
{
out->Next[i]->fail = out->fail->Next[i];
//如果还找到在其他地方找到和他一样的元素,那么我们就把失败指针指向这个元素,同时要设定合法状态
out->Next[i]->if_end = out->fail->Next[i]->if_end ? : out->Next[i]->if_end;
}
Queue[tail++] = out->Next[i];
}
else
{
if (out == root) out->Next[i] = root;
else out->Next[i] = out->fail->Next[i];
}
}
}

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

  

  参考: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

Match:Censored!(AC自动机+DP+高精度)(POJ 1625)的更多相关文章

  1. POJ 1625 Censored!(AC自动机+DP+高精度)

    Censored! Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 6956   Accepted: 1887 Descrip ...

  2. [POJ1625]Censored!(AC自动机+DP+高精度)

    Censored! Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10824   Accepted: 2966 Descri ...

  3. POJ1625 Censored! —— AC自动机 + DP + 大数

    题目链接:https://vjudge.net/problem/POJ-1625 Censored! Time Limit: 5000MS   Memory Limit: 10000K Total S ...

  4. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

  5. 对AC自动机+DP题的一些汇总与一丝总结 (2)

    POJ 2778 DNA Sequence (1)题意 : 给出m个病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个 关键字眼:不包含,个数,长度 DP[i][j] : 表示长 ...

  6. HDU 2457 DNA repair(AC自动机+DP)题解

    题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...

  7. Ural 1158. Censored! 有限状态自动机+DP+大整数

    Ural1158 看上去很困难的一道题. 原文地址 http://blog.csdn.net/prolightsfxjh/article/details/54729646 题意:给出n个不同的字符,用 ...

  8. HDU2296 Ring(AC自动机+DP)

    题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...

  9. HDU2457 DNA repair(AC自动机+DP)

    题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...

随机推荐

  1. WCF中安全的那些事!!!

    WCF默认绑定 WCF预先为所有绑定都定义了能满足大多数情形的配置模式,这样的话,只要没有修改某个配置参数,WCF就使用默认的安全模式. 先上一张默认的安全设置表格 绑定 设置 wsHttpBindi ...

  2. 在PHP中遍历数据库表中的数据

    数据库中的数据: //1.分别将每一行的每一列遍历出来 //mysql_fetch_row()函数在每一次遍历后会将指针向后自动移动一个单位 while($row=mysql_fetch_row($r ...

  3. OC第九节——协议与代理

    一.理解协议与代理 协议: 协议就是需要相互遵守的约定.规范:需要去实现协议中规定的方法. 代理: 代理是一个概念,很难用一个名词去定义(如我们可以说协议其实就是一个方法列表).它更像是一种关系,我要 ...

  4. 大数据之tachyon(未完版)

    1.内存文件存储系统 Tachyon是一个开源分布式存储系统,拥有高性能.高容错等优点.并具有类Java的文件API.插件式的底层文件系统.兼容Hadoop MapReduce和 Apache Spa ...

  5. 自定义Listview

    public class MyListView extends ListView { public MyListView(Context context) { super(context); } pu ...

  6. css弹性布局

    1.弹性布局是什么 在移动端一种方便的布局方式,打破了之前用浮动,定位的布局,更加灵活. 2.弹性布局的格式 包含父元素和子元素,有对应的属性应用在父元素和子元素达到布局的目的 3.父元素的属性 要开 ...

  7. Oracle sysdate 时间加减

    加法 select sysdate,add_months(sysdate,12) from dual;        --加1年 select sysdate,add_months(sysdate,1 ...

  8. BZOJ 1057: [ZJOI2007]棋盘制作

    Decsription 给你一个矩阵,求最大了 01相间 的矩阵. Sol DP+悬线法. 这是一个论文啊 <浅谈用极大化思想解决最大子矩形问题>--王知昆. 枚举每一根悬线,记录最左/右 ...

  9. BZOJ 2412: 电路检修

    Description [0,x]中全是1,其余全是0,每个点有一个权值,求最坏情况下得到x的最小权值. Sol DP+单调队列. 你可以去看我的这篇Blog...开这篇纯属为了骗访问... http ...

  10. 前端之js的常用用法

    js生成标签 // 将标签添加到i1里面 var tag = document.createElement('input'); tag.setAttribute('type', 'text'); ta ...