(AC自动机 + 矩阵加速)

题意:

    给定最多十个最长不超过10的病毒dna串,求长度为m(m < 2e9)的串中不含病毒的有多少。

分析:

   用自动机建立状态转移图,然后建立转移矩阵

   定义初始状态为[1 , 0 , 0 , 0  ....]代表当前长度为0可转移到各个状态的方案数目,然后乘上m次转移矩阵即答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
#define rep(i,n) for(int i = 0; i<(int)n;i++)
#define rep1(i,x,y) for(int i = x;i<(int)y;i++)

const int N = 115;
const int sigma_size = 4;
char str[N];
const char* sss ="ATCG";
struct Trie
{
    int ch[N][sigma_size];
    int val[N];
    int sz;
    void init()
    {
        sz = 1;
        memset(val , 0, sizeof(val));
        memset(ch[0] , 0,sizeof(ch[0]));
    }
    int idx(char x)
    {
        rep(i ,4) if(sss[i] == x) return i;
    }
    void insert(char* s, int v)
    {
        int n = strlen(s) , u = 0;
        rep(i , n)
        {
            int c = idx(str[i]);
            if(!ch[u][c])
            {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = 1;
    }
    int f[N];
    int last[N];
    void getfail()
    {
        f[0] = 0;
        queue<int> q;
        rep(i , sigma_size)
        {
            if(ch[0][i])
            {
                q.push(ch[0][i]);
                f[ch[0][i]] = last[ch[0][i]] = 0;
            }
        }
        while(!q.empty())
        {
            int r = q.front();
            q.pop();
            if (val[f[r]])
                val[r] = 1; 
            /* 特别注意这个细节,当在自动机中转移到的下一个状态不仅要求该点不是结尾,也要求
               该节点失配链中没有结尾*/
            for(int c = 0; c < sigma_size ; c++)
            {
                int u = ch[r][c];
                if(!u)
                {
                    ch[r][c] = ch[f[r]][c];
                    continue;
                }
                q.push(u);
                f[u] = ch[f[r]][c];
                last[u] = val[f[u]] ? f[u] : last[f[u]];
            }
        }
    }
} trie;
const int mod = 100000;
int n , m;
struct Matrix
{
    int m[N][N];
    Matrix()
    {
        memset(m , -1, sizeof(m));
    }
};
Matrix mul(Matrix A , Matrix B)
{
    Matrix C;
    rep(i , n) rep(j , n)
    {
        C.m[i][j] = 0;
        rep(k , n) C.m[i][j] = ((ll)C.m[i][j] + (ll)A.m[i][k] * B.m[k][j] % mod ) % mod;
    }
    return C;
}
Matrix pow_mul(Matrix A , int b)
{
    Matrix ans ;
    rep(i , n) rep(j ,n) ans.m[i][j] = (i == j);
    while(b > 0)
    {
        if(b & 1)  ans = mul(ans , A);
        b>>=1;
        A = mul(A,A);
    }
    return ans;
}
Matrix A;
void init()
{
    rep(i , n) rep(j , n) A.m[i][j] = 0;
    rep(i , n)
    {
        rep(j , sigma_size)
        {
            if(!trie.val[i] && !trie.val[trie.ch[i][j]])
            {
                A.m[i][trie.ch[i][j]]++;
            }
        }
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    trie.init();
    rep(i , n)
    {
        scanf("%s",str);
        trie.insert(str , i +1);
    }
    trie.getfail();
    n = trie.sz;
    init();
    Matrix B = pow_mul(A , m);
    ll ans = 0;
    rep(i , n) ans = (ans + B.m[0][i]) % mod;
    printf("%d\n",(int)ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值