码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 2243 (Aho-Corasick & 矩阵优化幂求和) - xgtao -

时间:2016-07-24 22:26:53      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

题目链接

 

给出n个模板串(n<6)求出长度为不超过l(l<2^31)的单词至少包含n个字串中的一个的种类数,对2^64取模。

 

首先有多个模板串,考虑Aho-Corasick,然后l数据范围提示要用log级别的算法,Trie中最常见的就是矩阵,那么接着分析,问出不超过l至少包含1个,那么我们把问题简化,我们会求出长度为l的不包含任意一个情况吧,不会的同学,传送过去,就用26^l-A^l,就得到长度为l包含至少一个的个数,那么就可以得到总体的算法,26^1+26^2+26^3+26^4+......26^l-(A^1+A^2+A^3+A^4+......A^l),矩阵的幂求和可以这样:

|A,1|^(n+1)  = |A^(n+1),1+A^1+A^2+A^3+A^4+......A^l|

|0,1|       |0          ,                                              1|

 

26^1+26^2+26^3+26^4+......26^l = 26*(1-26^l)/(1-26)

 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define LL unsigned long long
using namespace std;
const int N = 40;
const int alp = 26;
struct node{
	int id;
	bool flag;
	node *ch[alp],*fail;
	void init(){
		fail = NULL;
		for(int i = 0;i < alp;++i)ch[i] = NULL;
	}
}trie[N];
char s[250];
int m,ncnt;
LL l;
struct Matrix{
	LL map[2*N][2*N];
	void clear(){
		memset(map,0,sizeof(map));
	}
}c;

node *Newnode(){
	node *p = &trie[ncnt];
	p->init();
	p->id = ncnt++;
	return p;
}

void insert(node *root,char *s){
	node *p = root;
	while(*s != ‘\0‘){
		if(!p->ch[*s-‘a‘])p->ch[*s-‘a‘] = Newnode();
		p = p->ch[*s-‘a‘];
		++s;
	}
	p->flag = true;
}

void _build(node *root){
	memset(c.map,0,sizeof(c.map));
	queue <node *> q;
	q.push(root);
	while(!q.empty()){
		node *p = q.front();q.pop();
		for(int i = 0;i < alp;++i){
			if(p->ch[i]){
				node *next = p->fail;
				while(next && !next->ch[i])next = next->fail;
				p->ch[i]->fail = next ? next->ch[i]:root;
				if(p->ch[i]->fail->flag)p->ch[i]->flag = true;
				q.push(p->ch[i]);
			}
			else p->ch[i] = (p==root) ? root:p->fail->ch[i];
			if(!p->ch[i]->flag)++c.map[p->id][p->ch[i]->id];
		}
	}
}

Matrix Mul(Matrix x,Matrix y){
	Matrix res;
	for(int i = 0;i < 2*ncnt;++i){
		for(int j = 0;j < 2*ncnt;++j){
			res.map[i][j] = 0;
			for(int k = 0;k < 2*ncnt;++k){
				res.map[i][j] = (res.map[i][j]+y.map[k][j]*x.map[i][k]);
			}
		}
	}
	return res;
}

Matrix Pow(Matrix x,LL n){
	Matrix res;
	res.clear();
	for(int i = 0;i < 2*ncnt;++i)res.map[i][i] = 1;
	while(n){
		if(n&1)res = Mul(res,x);
		x = Mul(x,x);
		n >>=1;
	}
	return res;
}


Matrix Sum(Matrix x,LL l){
	Matrix ret;
	for(int i = 0;i < ncnt;++i){
		for(int j = 0;j < ncnt;++j){
			ret.map[i][j] = c.map[i][j];
		}
	}
	for(int i = 0;i < ncnt;++i){
		for(int j = ncnt;j < 2*ncnt;++j){
			ret.map[i][j] = ( i == (j-ncnt));
		}
	}
	for(int i = ncnt;i < 2*ncnt;++i){
		for(int j = 0;j < ncnt;++j){
			ret.map[i][j] = 0;
		}
	}
	for(int i = ncnt;i < 2*ncnt;++i){
		for(int j = ncnt;j < 2*ncnt;++j){
			ret.map[i][j] = ( (i-ncnt) == (j-ncnt));
		}
	}
	ret = Pow(ret,l+1);//l+1可能要爆Int 
	return ret;
}

LL fastp(int x,int n){
	LL res = 1;
	LL f = (LL)x;
	while(n){
		if(n&1)res = res*f;
		f = f*f;
		n >>= 1;
	}
	return res;
}

void _pre(){
	for(int i = 0;i < ncnt;++i){
		if(trie[i].flag){
			for(int k = 0;k < ncnt;++k)c.map[i][k] = 0;
			for(int k = 0;k < ncnt;++k)c.map[k][i] = 0;
		}
	}
}

int main(){
	while(scanf("%d%I64u",&m,&l) != EOF){
		ncnt = 0;
		memset(trie,0,sizeof(trie));
		node *root = Newnode();
		for(int i = 0;i < m;++i){
			scanf("%s",s);
			insert(root,s);
		}
		_build(root);
		LL ans = 0;
		_pre();
		Matrix res = Sum(c,l);
		for(int i = ncnt;i < 2*ncnt;++i){
			ans += res.map[0][i];
		}
		ans -= 1;
		ans = (LL)26*(fastp(26,l)-1)*10330176681277348905LL-ans;
		//10330176681277348905LL是(x/25)%2^64的x的逆元 
		cout<<ans<<endl;
	}
	return 0;
}

  

                                          

                                            

hdu 2243 (Aho-Corasick & 矩阵优化幂求和) - xgtao -

标签:

原文地址:http://www.cnblogs.com/xgtao984/p/5701648.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!