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

题目链接

给出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;
}

  

                                          

                                            

时间: 2024-12-19 18:02:14

hdu 2243 (Aho-Corasick & 矩阵优化幂求和) - xgtao -的相关文章

hdu 2243 AC自动机 + 矩阵快速幂

// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 //

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的tire图详解可以点击这里,往下面翻,这个博主的图对于tire图讲的非常详细. 知道了什么是tire图,理解了tire图后,后面的AC自动机的题目才能写. AC自动机的灵魂应该就是tire图 然后问题就变成了,得到了一个可达矩阵后,如何求方案数呢? 这个n = 2000000000 这咋办呢? 给定一

HDU 2243 ( Trie图 矩阵构造幂和 )

题意 :  长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为(2个) aa,ab, (26个)aaa,aab,aac...aaz, (26个)aba,abb,abc...abz, (25个)baa,caa,daa...zaa, (25个)bab,cab,dab...zab. 分析: 我们可以用Tire图跑矩阵快速幂的方法,去求长度为n不包含给定单词的词

考研路茫茫――单词情结 HDU - 2243(ac自动机 + 矩阵快速幂)

考研路茫茫--单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6853    Accepted Submission(s): 2383 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了.一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如

HDU 2254 奥运(矩阵快速幂+二分等比序列求和)

HDU 2254 奥运(矩阵快速幂+二分等比序列求和) ACM 题目地址:HDU 2254 奥运 题意: 中问题不解释. 分析: 根据floyd的算法,矩阵的k次方表示这个矩阵走了k步. 所以k天后就算矩阵的k次方. 这样就变成:初始矩阵的^[t1,t2]这个区间内的v[v1][v2]的和. 所以就是二分等比序列求和上场的时候了. 跟HDU 1588 Gauss Fibonacci的算法一样. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * B

HDU 2604 Queuing (矩阵快速幂)

HDU 2604 Queuing (矩阵快速幂) ACM 题目地址:HDU 2604 Queuing 题意: n个人排队,f表示女,m表示男,包含子串'fmf'和'fff'的序列为O队列,否则为E队列,有多少个序列为E队列. 分析: 矩阵快速幂入门题. 下面引用巨巨解释: 用f(n)表示n个人满足条件的结果,那么如果最后一个人是m的话,那么前n-1个满足条件即可,就是f(n-1): 如果最后一个是f那么这个还无法推出结果,那么往前再考虑一位:那么后三位可能是:mmf, fmf, mff, fff

HDU 2604 Queuing,矩阵快速幂

题目地址:HDU 2604 Queuing 题意: 略 分析: 易推出:   f(n)=f(n-1)+f(n-3)+f(n-4) 构造一个矩阵: 然后直接上板子: /* f[i] = f[i-1] + f[i-3] + f[i-4] */ #include<cstdio> #include<cstring> using namespace std; const int N = 4; int L, M; struct mtx { int x[N+1][N+1]; mtx(){ mem

Recursive sequence HDU - 5950 (递推 矩阵快速幂优化)

题目链接 F[1] = a, F[2] = b, F[i] = 2 * F[i-2] + F[i-1] + i ^ 4, (i >= 3) 现在要求F[N] 类似于斐波那契数列的递推式子吧, 但是N最大能到int的最大值, 直接循环推解不了 所以就得用矩阵快速幂咯 现在就看转移矩阵长什么样了 Mi表示要求的矩阵 转移矩阵用A表示 A * Mi = Mi+1 矩阵Mi里面至少得有 F[i-1] F[i-2] i ^ 4 Mi+1就相应的有 F[i] F[i-1] (i+1)^4 (i+1)^4 =

HDU 5950 Recursive sequence 矩阵快速幂

http://acm.hdu.edu.cn/showproblem.php?pid=5950 一开始以为i^4不能矩阵快速幂,但是结论是可以得,那么要怎么递推呢? 矩阵快速幂的思路都是一样的,matrix_a * matrix_b ^ n 其中,想要维护什么,就在matrix_a写,比如现在是F[n - 1], F[n - 2],我想要递推到下一项,那么就 会变成F[n], F[n - 1],这个时候,你就要寻找一下F[n]和F[n - 1]有什么关系. i^4也一样,想要从i^4 递推到 (i