hdu2604---Queuing(AC自动机+矩阵)

Problem Description

Queues and Priority Queues are data structures which are known to most computer scientists. The Queue occurs often in our daily life. There are many people lined up at the lunch time.

Now we define that ‘f’ is short for female and ‘m’ is short for male. If the queue’s length is L, then there are 2L numbers of queues. For example, if L = 2, then they are ff, mm, fm, mf . If there exists a subqueue as fmf or fff, we call it O-queue else it is a E-queue.

Your task is to calculate the number of E-queues mod M with length L by writing a program.

Input

Input a length L (0 <= L <= 10 6) and M.

Output

Output K mod M(1 <= M <= 30) where K is the number of E-queues with length L.

Sample Input

3 8 4 7 4 8

Sample Output

6 2 1

Author

WhereIsHeroFrom

Source

HDU 1st “Vegetable-Birds Cup” Programming Open Contest

Recommend

lcy | We have carefully selected several similar problems for you: 1588 1757 2606 2276 2603

设dp[i][j]表示长度为i,在节点j时,不含非法串的方案数

由于n很大,直接递推会超时,所以用矩阵来加速

如果节点i可以转移到节点j,那么A.mat[i][j] = 1

最后快速幂求出A^n次,然后统计答案即可

/*************************************************************************
    > File Name: hdu2604.cpp
    > Author: ALex
    > Mail: [email protected]
    > Created Time: 2015年03月10日 星期二 20时30分24秒
 ************************************************************************/

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

const int MAX_NODE = 20;
const int CHILD_NUM = 2;

int m;

struct MARTIX
{
    int mat[MAX_NODE][MAX_NODE];
};

MARTIX mul (MARTIX a, MARTIX b, int L)
{
    MARTIX c;
    for (int i = 0; i < L; ++i)
    {
        for (int j = 0; j < L; ++j)
        {
            c.mat[i][j] = 0;
            for (int k = 0; k < L; ++k)
            {
                c.mat[i][j] += a.mat[i][k] * b.mat[k][j];
                c.mat[i][j] %= m;
            }
        }
    }
    return c;
}

MARTIX fastpow (MARTIX ret, int n, int L)
{
    MARTIX ans;
    for (int i = 0; i < L; ++i)
    {
        for (int j = 0; j < L; ++j)
        {
            ans.mat[i][j] = (i == j);
        }
    }
    while (n)
    {
        if (n & 1)
        {
            ans = mul (ans, ret, L);
        }
        n >>= 1;
        ret = mul (ret, ret, L);
    }
    return ans;
}

struct AC_Automation
{
    int next[MAX_NODE][CHILD_NUM];
    int fail[MAX_NODE];
    int end[MAX_NODE];
    int root, L;

    int newnode()
    {
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L - 1;
    }

    void init()
       {
             L = 0;
            root = newnode();
        }

    void Build_Trie(char buf[])
    {
        int now = root;
        int len = strlen(buf);
        for (int i = 0; i < len; ++i)
        {
            if (next[now][buf[i] - ‘0‘] == -1)
            {
            next[now][buf[i] - ‘0‘] = newnode();
            }
            now = next[now][buf[i] - ‘0‘];
        }
        end[now] = 1;
        }

    void Build_AC()
    {
        queue <int> qu;
        fail[root] = root;
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            if (next[root][i] == -1)
            {
                next[root][i] = root;
            }
            else
            {
                fail[next[root][i]] = root;
                qu.push(next[root][i]);
            }
        }
        while (!qu.empty())
        {
            int now = qu.front();
            qu.pop();
            if (end[fail[now]])
            {
                end[now] = 1;
            }
            for (int i = 0; i < CHILD_NUM; ++i)
            {
                if (next[now][i] == -1)
                {
                    next[now][i] = next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    qu.push(next[now][i]);
                }
            }
        }
    }

    void solve (int n)
    {
        MARTIX ret;
        for (int i = 0; i < L; ++i)
        {
            for (int j = 0; j < L; ++j)
            {
                ret.mat[i][j] = 0;
            }
        }
        for (int i = 0; i < L; ++i)
        {
            if (end[i])
            {
                continue;
            }
            for (int j = 0; j < CHILD_NUM; ++j)
            {
                if (end[next[i][j]])
                {
                    continue;
                }
                ret.mat[i][next[i][j]] = 1;
            }
        }
        MARTIX c = fastpow (ret, n, L);
        int ans = 0;
        for (int i = 0; i < L; ++i)
        {
            ans += c.mat[0][i];
            ans %= m;
        }
        printf("%d\n", ans);
    }
}AC;

int main ()
{
    int L;
    char buf1[] = "010";
    char buf2[] = "000";
    while (~scanf("%d%d", &L, &m))
    {
        AC.init();
        AC.Build_Trie (buf1);
        AC.Build_Trie (buf2);
        AC.Build_AC();
        AC.solve (L);
    }
    return 0;
}
时间: 2024-10-17 09:20:52

hdu2604---Queuing(AC自动机+矩阵)的相关文章

poj 2778 AC自动机 + 矩阵快速幂

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

poj2778DNA Sequence(AC自动机+矩阵乘法)

链接 看此题前先看一下matrix67大神写的关于十个矩阵的题目中的一个,如下: 经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j.令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点).类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数.同理,如果要求经过k步的路径数,我们只需要二分求出A^k

spoj 1676 AC自动机+矩阵快速

Text Generator Time Limit: 1386MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Submit Status Description LoadingTime has been given a task these days. He is required to write a tool called Text Generator. This software is widely used amon

hdu2243 ac自动机+矩阵连乘

http://acm.hdu.edu.cn/showproblem.php?pid=2243 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包

POJ 2778 DNA Sequence (AC自动机 + 矩阵快速幂)

题目链接:DNA Sequence 解析:AC自动机 + 矩阵加速(快速幂). 这个时候AC自动机 的一种状态转移图的思路就很透彻了,AC自动机就是可以确定状态的转移. AC代码: #include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int MOD = 100000; struct Matrix{ int ma

POJ POJ 2778 DNA Sequence AC自动机 + 矩阵快速幂

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就

hdu 2243 AC自动机 + 矩阵快速幂

// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 //

BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法

题意:链接略 方法: AC自动机+矩阵乘法 解析: 和POJ 2778 一样的题. 大概的思路就是我们建AC自动机的时候需要注意如果某个点是一个串的结尾的话,那么下面的节点都要看成结尾节点. 然后按照AC自动机赋一下矩阵内部值就好了. 赋的矩阵代表从一个节点走一步走到另一个节点有多少方案. 然后经典模型,矩阵的n次方即可. 代码: #include <queue> #include <cstdio> #include <cstring> #include <ios

POJ 2778 AC自动机+矩阵幂 不错的题

http://poj.org/problem?id=2778 有空再重新做下,对状态图的理解很重要 题解: http://blog.csdn.net/morgan_xww/article/details/7834801 另外做了矩阵幂的模板: //ac.sz是矩阵的大小 void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y { ll tmp[MAXNODE][MAXNODE]; for(in

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

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