题意:
给定最多十个最长不超过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;
}
本文介绍了一种使用自动机和矩阵快速幂解决病毒DNA串匹配问题的方法,通过构建状态转移图和矩阵运算,高效地计算出长度为m的字符串中不包含给定病毒DNA子串的数量。
858

被折叠的 条评论
为什么被折叠?



