HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)

题目链接

错的上头了...

这题是DNA的加强版,26^1 +26^2... - A^1-A^2...

先去学了矩阵的等比数列求和,学的是第二种方法,扩大矩阵的方法。剩下就是各种模板,各种套。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
#define LL unsigned __int64
#define N 100001
int t,trie[N][26],que[N],o[N],fail[N];
LL p[201][201],mat[201][201];
void CL()
{
memset(trie,-1,sizeof(trie));
memset(p,0,sizeof(p));
memset(o,0,sizeof(o));
t = 1;
}
void insert(char *s)
{
int i,root,len;
len = strlen(s);
root = 0;
for(i = 0; i < len; i ++)
{
if(trie[root][s[i]-‘a‘] == -1)
trie[root][s[i]-‘a‘] = t ++;
root = trie[root][s[i]-‘a‘];
}
o[root] = 1;
}
void build_ac()
{
int head,tail,front,i;
head = tail = 0;
for(i = 0; i < 26; i ++)
{
if(trie[0][i] != -1)
{
fail[trie[0][i]] = 0;
que[tail++] = trie[0][i];
}
else
{
trie[0][i] = 0;
}
}
while(head != tail)
{
front = que[head++];
if(o[fail[front]])
o[front] = 1;
for(i = 0; i < 26; i ++)
{
if(trie[front][i] != -1)
{
que[tail++] = trie[front][i];
fail[trie[front][i]] = trie[fail[front]][i];
}
else
{
trie[front][i] = trie[fail[front]][i];
}
}
}
}
void work()
{
int i,j;
for(i = 0; i < t; i ++)
{
if(o[i]) continue;
for(j = 0; j < 26; j ++)
{
if(o[trie[i][j]]) continue;
p[i][trie[i][j]] ++;
}
}
for(i = 0; i < t; i ++)
{
p[i][t+i] = p[t+i][t+i] = 1;
}
t <<= 1;
}
LL qmod(LL n)
{
int i,j,k;
LL c[201][201],ans = 0;
while(n)
{
if(n&1)
{
memset(c,0,sizeof(c));
for(i = 0; i < t; i ++)
{
for(j = 0; j < t; j ++)
{
for(k = 0; k < t; k ++)
{
c[i][j] += mat[i][k]*p[k][j];
}
}
}
memcpy(mat,c,sizeof(mat));
}
memset(c,0,sizeof(c));
for(i = 0; i < t; i ++)
{
for(j = 0; j < t; j ++)
{
for(k = 0; k < t; k ++)
{
c[i][j] += p[i][k]*p[k][j];
}
}
}
memcpy(p,c,sizeof(p));
n >>= 1;
}
for(i = t/2; i < t; i ++)
{
ans += mat[0][i];
}
return ans-1;
}

LL fastmod(LL a,LL k)
{
LL b = 1;
while(k)
{
if(k&1)
b = a*b;
a = a*a;
k = k/2;
}
return b;
}
LL getnum(LL p,LL k)
{
if (k <= 0) return 1;
if (k%2 == 0)
return ((getnum(p,k/2 - 1))*((1 + fastmod(p,k/2 + 1))) + fastmod(p,k/2));
else
return ((getnum(p,(k + 1)/2 - 1))*((1 + fastmod(p,(k + 1)/2))));
}
int main()
{
int i,j,m;
LL n;
char ch[101];
while(scanf("%d%I64u",&m,&n)!=EOF)
{
CL();
for(i = 1; i <= m; i ++)
{
scanf("%s",ch);
insert(ch);
}
build_ac();
work();
for(i = 0; i < t; i ++)
{
for(j = 0; j < t; j ++)
{
mat[i][j] = (i == j);
}
}
printf("%I64u\n",getnum(26,n)-1-qmod(n+1));
}
}

HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)

时间: 2024-10-08 20:49:54

HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)的相关文章

hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <231)的单词中至少含有一个词根的单词个数:结果mod 264. 基础:poj 2778DNA 序列求的是给定长度不含模式串的合法串的个数:串长度相当,都到了int上界了: 1.mod 264直接使用unsigned long long自然溢出即可:说的有些含蓄..并且也容易想到是直接使用内置类型,要不然高精度的

HDU 2243 考研路茫茫――单词情结 (AC自动机 + dp)

HDU 2243 考研路茫茫――单词情结 题意:给定一些词根,如果一个单词包含有词根,则认为是有效的.现在问长度不超过L的单词里面,有多少有效的单词? 思路:这道题和POJ 2778是同样的思路.POJ 2778是要找出长度为L的单词里面有多少无效的单词.那么根据同样的方法构造矩阵,然后所有无效的单词个数为 A + A^2 + ... + A^l 个.而所有单词的个数为26 + 26^2 + - + 26^l 个.两个减一下即为答案. 矩阵连乘求和:I + A^2 + A^3 + ... + A

hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)

考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4843    Accepted Submission(s): 1527 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了.一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)

和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_sub(1)+solve(2)+...+solve_sub(n)).前者构造f[i]=f[i-1]*26+26然后矩阵快速幂即可(当然也可以分治的方法).后者即构造出dp矩阵p,然后计算(p^1+p^2+...+p^n),对其分治即可. 代码如下: 1 #include <stdio.h> 2 #

Hdu 2243 考研路茫茫——单词情结 (AC自动机+矩阵)

哎哟喂,中文题...不说题意了. 首先做过POJ 2778可以知道AC自动机是可以求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用所有给的病毒串建一个AC自动机,然后将AC自动机上所有非单词节点连一个边. 离散数学中有说道,如果矩阵A 中的 [i][j] 表示 i节点通过一条边可以走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边可以走到j节点的方法数. 既然知道这个方法,我们就明确要求什么. ans= 26+26^2+26^3+

HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)

背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不

HDU 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意: 给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数. 思路: 如果做过poj2778的话,那么这题相对来说就会容易一些. 如果直接去计算的话,情况很复杂,和poj2778一样,我们先求出不包含模式串的个数,最后只需要相减就可以. 因为这道题目长度只要不超过n就可以,所以在构造矩阵的时候需要多加一列,该列值每行全设为1(这样最后一列的值就是对上一个矩阵每一行的和,完美计算了了各种长度

Hdu 2243 考研路茫茫——单词情结 (AC自己主动机+矩阵)

哎哟喂.中文题. . .不说题意了. 首先做过POJ 2778能够知道AC自己主动机是能够求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用全部给的病毒串建一个AC自己主动机.然后将AC自己主动机上全部非单词节点连一个边. 离散数学中有说道.假设矩阵A 中的 [i][j] 表示 i节点通过一条边能够走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边能够走到j节点的方法数. 既然知道这种方法.我们就明白要求什么. ans= 26+26