AC自动机加矩阵

#include<iostream>
#include<queue>
#include<map>
#include<cmath>
using namespace std;
#define N 35
#define M 26
#define FF(i,n) for(int i=0;i<n;i++)
int tree[N][M];
int Node;
int fail[N];
bool isword[N];
int index[N];
void init(){
	Node=0;
	memset(tree[0],0,sizeof(tree[0]));
	memset(isword,false,sizeof(isword));
}
void insert(char *p){
	int root=0;
	int len=strlen(p);
	for(int i=0;i<len;i++){
		int c=p[i]-'a';
		if(!tree[root][c]){
			tree[root][c]=++Node;
			memset(tree[Node],0,sizeof(tree[Node]));
		}
		root=tree[root][c];
	}
	isword[root]=true;
}
void AC(){
	queue<int> q;
	for(int i=0;i<M;i++)
		if(tree[0][i]){
			fail[tree[0][i]]=0;
			q.push(tree[0][i]);
		}
	while(!q.empty()){
		int p=q.front();
		q.pop();
		for(int i=0;i<M;i++){
			if(tree[p][i]){
				int v=tree[p][i];
				q.push(v);
				fail[v]=tree[fail[p]][i];
				isword[v]|=isword[fail[v]];
			}
			else
				tree[p][i]=tree[fail[p]][i];
		}
	}
}


int len;  
struct Matrix_Cal{  
    unsigned __int64 mat[N][N];
}e,Init,tp1,tp2;
Matrix_Cal operator+(Matrix_Cal a ,Matrix_Cal b){  
    Matrix_Cal c;  
    FF(i,len)FF(j,len)  
        c.mat[i][j]=a.mat[i][j]+b.mat[i][j];  
    return c;  
}  
Matrix_Cal operator*(Matrix_Cal a , Matrix_Cal b){  
    Matrix_Cal c;  
    int i,j,k;  
    FF(i,len)FF(j,len)  
        c.mat[i][j] = 0;  
    FF(i,len)FF(k,len) if(a.mat[i][k])FF(j,len) if(b.mat[k][j])  
        c.mat[i][j]=c.mat[i][j]+a.mat[i][k]*b.mat[k][j];  
    return c;  
}  
Matrix_Cal operator^(Matrix_Cal a , int b){  
    Matrix_Cal c=e, q=a;  
    for(;b;b>>=1){  
        if(b&1) c=c*q;  
        q=q*q;  
    }  
    return c;  
}  
Matrix_Cal Matrix_Sum(Matrix_Cal a ,int b){
    int n=0,s[N];
    int i;
    Matrix_Cal tp1,tp2;
    while(b>0){ 
        s[n++]=b&1;
        b>>=1;
    }
    tp1=tp2=a;
    for(i=n-2;i>=0;i--){
        tp1=tp1*(tp2+e);
        tp2=tp2*tp2;
        if(s[i]){
            tp2=tp2*a;
            tp1=tp1+tp2;
        }
    }
    return tp1;
}


void creat(){
	int ind=0;
	int i,j;
	memset(Init.mat,0,sizeof(Init.mat));
	FF(i,N)FF(j,N) e.mat[i][j]=(i==j);
	memset(index,0,sizeof(index));
	for(i=0;i<=Node;i++)
		if(!isword[i])
			index[i]=ind++;
	for(i=0;i<=Node;i++)
		if(!isword[i])
			for(j=0;j<M;j++)
				if(!isword[tree[i][j]])
					Init.mat[index[i]][index[tree[i][j]]]++;
}


int main(void){
	int n;
	int m;
	char ch[10];
	while(~scanf("%d%d",&n,&m)){
		init();
		for(int i=0;i<n;i++){
			scanf("%s",ch);
			insert(ch);
		}
		AC();
		creat();
		int i,j;
		len=N;
		tp1=Matrix_Sum(Init,m);		
		Init.mat[0][0]=26;
		len=1;
		tp2=Matrix_Sum(Init,m);
		for(int i=0;i<N;i++)
			tp2.mat[0][0]-=tp1.mat[0][i];
		printf("%I64u\n",tp2.mat[0][0]);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值