【题意】给出M(<=10)个病毒DNA字符串,每个串长度不超过10。然后给出一个长度为N(<=2000000000)的只能由’A’,’C’,’T’,’G’组成的DNA字符串,问能 组成多少个不包含病毒串的字符串。
【分析】n的范围很大,需要快速矩阵幂,但是怎么构建矩阵呢;在《十个利用矩阵乘法解决的经典题目(Maxtrix67)》这篇文章中有提到有向图的矩阵,从任意一点到另外点经过几步有几种走法,可以建一个邻接矩阵,则通过k步就是矩阵的k次方;而这题可以用AC自动机建立有向图矩阵,稍微有些不同的是这个 矩阵初始距离的两点之间的边数,构建fail指针的时候也需要加上判断前缀和是否含有病毒。这样最后对状态图建的二维矩阵的n次方就是最后初始点0到各点之间的转移可能数。
【AC CODE】187ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> #include <bitset> //#include <unordered_set> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 10*10+10; const LL MOD = 100000; int id[300]; struct Trie{ int cnt; int ch[MAXN][4], fail[MAXN]; bool end[MAXN]; int newnode() { clc(ch[cnt],-1); end[cnt++] = 0; return cnt-1; } void init() { cnt = 0; newnode(); clc(end,0); } void insert(char *s) { int u = 0,len = strlen(s); rep(i,0,len) { int& c = ch[u][id[s[i]]]; if(-1 == c) c = newnode(); u = c; } end[u] = true; } void get_fail() { queue<int> q; fail[0] = 0; rep(i,0,4) { int& c = ch[0][i]; if(~c) { fail[c] = 0; q.push(c); } else c = 0; } while(!q.empty()) { int u = q.front();q.pop(); rep(i,0,4) { int& c = ch[u][i]; int p = ch[fail[u]][i]; if(end[p]) end[c] = true;//当前面字符串的后缀为病毒串时该串也不能用 if(~c) { fail[c] = p; q.push(c); } else c = p; } } } }ac; struct MATRIX{ LL num[MAXN][MAXN]; }x; int cnt; MATRIX mul_mod(const MATRIX& a, const MATRIX& b) { MATRIX ans; clc(ans.num,0); rep(i,0,cnt) { rep(j,0,cnt) { rep(k,0,cnt) ans.num[i][j] += a.num[i][k]*b.num[k][j]; ans.num[i][j] %= MOD; } } return ans; } MATRIX pow_mod(MATRIX x, int n) { MATRIX ans; clc(ans.num,0); rep(i,0,cnt) ans.num[i][i] = 1; while(n) { if(n&1) ans = mul_mod(ans,x); x = mul_mod(x,x); n >>= 1; } return ans; } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif id['A'] = 0,id['C'] = 1, id['T'] = 2, id['G'] = 3; int m,n; scanf("%d %d", &m, &n); ac.init(); char str[20]; rep(i,0,m) { scanf("%s", str); ac.insert(str); } ac.get_fail(); cnt = ac.cnt; clc(x.num,0); rep(i,0,cnt) { rep(j,0,4) if(!ac.end[i] && !ac.end[ac.ch[i][j]]) x.num[i][ac.ch[i][j]]++; } x = pow_mod(x,n); LL ans = 0; rep(i,0,cnt) ans += x.num[0][i]; printf("%I64d\n", ans%MOD); return 0; }