【poj2778】【AC自動機】【DFA】【矩陣乘法】DNA Sequence

求長度爲n的串中不包含模式串的串的數目

首先將模式串建成AC自動機,將模式串標記,這裏需要注意的是,如果一個節點的失敗指針也指向了一個模式串,那麼該節點也需要被標記。

建好AC自動機後,我們建立了轉化關係,然後我們就可以使用DP的方式計算答案

考慮到n的範圍很大,所以我們將所有不包含模式串的轉化關係構建一個矩陣,使用矩陣快速冪求出長度爲n的串的方案數,累加即可。

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100 + 10;
const int child_num = 4;
const int mo = 100000;
struct Matrix
{
	long long v[maxn][maxn];
	int x,y;
	Matrix()
	{
		memset(v,0,sizeof(v));
		x = y = 0;
	}
}mat;
char tmp[maxn];
int n,m,sz,matnum;
int matcal[maxn];
class ACAutumaton
{
public:
	int chd[maxn][child_num];
	int fail[maxn],val[maxn];
	int Q[maxn],ID[maxn];
	int cnt;
	void Reset()
	{
		memset(fail,0,sizeof(fail));
		ID['A'] = 0;ID['C'] = 1;
		ID['T'] = 2;ID['G'] = 3;
		sz = 1;
	}
	void Insert(char *a,int key)
	{
		int p = 0;
		for(;*a ;a++)
		{
			int c = ID[*a];
			if(!chd[p][c])
			{
				memset(chd[sz],0,sizeof(chd[sz]));
				val[sz] = 0;
				chd[p][c] = sz ++;
			}
			p = chd[p][c];
		}
		val[p] = key;
	}
	void Construct()
	{
		int *s = Q,*e = Q;
		for(int i = 0;i < child_num;i++)
		{
			if(chd[0][i])
			{
				fail[ chd[0][i] ] = 0;
				*e++ = chd[0][i];
			}
		}
		while(s != e)
		{
			int u = *s++;
			for(int i = 0;i < child_num;i++)
			{
				int &v = chd[u][i];
				if(v)
				{
					*e++ = v;
					fail[v] = chd[ fail[u] ][i];
					val[v] |= val[fail[v]];
				}
				else v = chd[ fail[u] ][i];
			}
		}
	}
}AC;
void init()
{
	freopen("poj2778.in","r",stdin);
	freopen("poj2778.out","w",stdout);
}

void work()
{
	memset(matcal,0,sizeof(matcal));
	matnum = 0;
	for(int i = 0;i < sz;i++)
		if(!AC.val[i])matcal[i] = ++matnum;
	mat.x = matnum;mat.y = matnum;
	for(int i = 0;i < sz;i++)
	{
		if(!AC.val[i])
		{
			for(int j = 0;j < child_num;j++)
			{
				if(!AC.val[AC.chd[i][j]])
					mat.v[matcal[i]][matcal[AC.chd[i][j]]]++;
			}
		}
	}
}

Matrix mtMul(Matrix A,Matrix B)
{
	if(!A.x || !A.y)return B;
	Matrix C;
	C.x = A.x;C.y = B.y;
	for(int i = 1;i <= A.x;i++)
	{
		for(int j = 1;j <= B.y;j++)
		{
			for(int k = 1;k <= A.y;k++)
			{
				C.v[i][j] = (A.v[i][k] * B.v[k][j] + C.v[i][j]) % mo;
			}
		}
	}
	return C;
}

Matrix mtPow(Matrix A,int k)
{
	Matrix ret;
	while(k)
	{
		if(k & 1)ret = mtMul(ret,A);
		k >>= 1;
		A = mtMul(A,A);
	}
	return ret;
}

void readdata()
{
	scanf("%d%d",&m,&n);
	AC.Reset();
	for(int i = 1;i <= m;i++)
	{
		scanf("%s",tmp);
		AC.Insert(tmp,1);
	}
}

void solve()
{
	AC.Construct();
	work();
	Matrix tmp = mtPow(mat,n);
	int ans = 0;
	for(int i = 1;i <= matnum;i++)
	{
		ans += tmp.v[1][i];	
		if(ans >= mo)ans -= mo;
	}
	printf("%d\n",ans);
}

int main()
{
	init();
	readdata();
	solve();
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章