您的位置:首页 > 其它

HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂+等比矩阵求和)

2017-11-06 20:43 351 查看

Problem Description

背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。

一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如”ab”,放在单词前一般表示”相反,变坏,离去”等。

于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过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。

这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。

Input

本题目包含多组数据,请处理到文件结束。 每组数据占两行。 第一行有两个正整数N和L。(0

Output

对于每组数据,请在一行里输出一共可能的单词数目。 由于结果可能非常巨大,你只需要输出单词总数模2^64的值。

Sample Input

2 3
aa ab
1 2
a


Sample Output

104
52


思路

首先,在做这个题之前,应该先做一下POJ2778 DNA Sequence(AC自动机+矩阵快速幂)

这两个题思想是一样的,这个是上一题的加强版

先说题意,这个题是让你求包含词根的,所有的长度小于等于m的单词种数(POJ2778的长度是固定的)

首先这一题要注意,要对264次方取模,那么我们把数据类型改成
unsinged long long
就可以完美解决这个问题,用
unsigned long long
会自动截断,相当于对264次方取模

我们求的是包含词根长度小于等于m的单词一共有多少个,那么我们先把所有的单词情况求出来(不管是否包含词根),也就是:

261+262+263+...+26m

个,我们假设包含词根的是病毒串,然后就可以求出来不包含词根的有多少种,所以我们只需要用全集减去不包含词根的种数就得到了包含词根的种类数

我们以样例来进行解释:

首先画出这个Trie树:



然后像POJ2778一样,定义矩阵:

mat[i][j]:代表从状态i到状态j,只走一步,有几种走法

那么我们根据这个图可以构建出一个矩阵:

25 1 0 0
24 0 1 1
24 0 1 1
25 1 0 0


我们删去它的病毒序列(参考一下POJ2778),所得到的矩阵为:

25 1 0 0
24 0 0 0
0  0 0 0
0  0 0 0


我们设这个矩阵为A,那么我们要求出从长度为1到长度为m的所有的不包含词根的串,我们就要求出:

A1+A2+A3+...+Am

那么我们怎么求这个矩阵和呢?这时候就要用到等比矩阵求和的知识:

参考:等比数列二分求和

我们要引入一个公式:





通过这个方法就可以求出某个矩阵的连续指数和,然后减去E就可以了

那么我们就可以求L+1次方就可以,因为我们最后只是求的是矩阵的第一列,所以在最后的答案中-1就行

,经过这个公式的变形,我们的矩阵变成这样:

25 1 0 0 1
24 0 0 0 1
0  0 0 0 1
0  0 0 0 1
0  0 0 0 1


我们只需要求出它的m次方,然后再把他第一行的和算出来,减去1,就是A1+A2+A3+...+Am的答案

那么现在我们已经求出了A1+A2+A3+...+Am的和,我们要做的是用261+262+263+...+26m的结果把他减去,那么我们怎么求261+262+263+...+26m的值呢?

我们继续用矩阵快速幂,我们构建一个2*2的矩阵:

26 0
1  1


求出它的m次方,它的第一列的和再减去1,就是261+262+263+...+26m的结果。



res=A1+A2+A3+...+Amans=261+262+263+...+26m

我们只需要算出
ans-res
的值就是答案

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef unsigned long long ull;
using namespace std;
const int N=50;
struct Matrix
{
ull mat

;
int n;
Matrix() {}
Matrix(int _n)
{
n=_n;
mem(mat,0);
}
Matrix operator *(const Matrix &b)const
{
Matrix ret=Matrix(n);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
for(int k=0; k<n; k++)
ret.mat[i][j]+=mat[i][k]*b.mat[k][j];
return ret;
}
};
ull pow_m(ull a,int n)
{
ull ans=1;
ull tmp=a;
while(n)
{
if(n&1)
ans*=tmp;
tmp*=tmp;
n>>=1;
}
return ans;
}
Matrix pow_M(Matrix a,int n)
{
Matrix ans=Matrix(a.n);
for(int i=0; i<a.n; i++)
ans.mat[i][i]=1;
Matrix tmp=a;
while(n)
{
if(n&1)
ans=ans*tmp;
tmp=tmp*tmp;
n>>=1;
}
return ans;
}
struct dicTree
{
int fail
,next
[26];
bool end
;
int root,sz;
int newnode()
{
for(int i=0; i<26; i++)
next[sz][i]=-1;
end[sz++]=false;
return sz-1;
}
void init()
{
sz=0;
root=newnode();
}
void insert(char *s)
{
int now=root;
int len=strlen(s);
for(int i=0; i<len; i++)
{
int to=s[i]-'a';
if(next[now][to]==-1)
next[now][to]=newnode();
now=next[now][to];
}
end[now]=true;
}
void build()
{
queue<int>q;
fail[root]=root;
for(int i=0; i<26; i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
q.push(next[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
if(end[fail[now]])
end[now]=true;
for(int i=0; i<26; i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
q.push(next[now][i]);
}
}
}
}
Matrix get_mat()
{
Matrix ret=Matrix(sz+1);
for(int i=0; i<sz; i++)
for(int j=0; j<26; j++)
if(end[next[i][j]]==false&&end[i]==false)
ret.mat[i][next[i][j]]++;
for(int i=0; i<sz+1; i++)
ret.mat[i][sz]=1;
return ret;
}
};
dicTree ac;
char s
;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
ac.init();
for(int i=0; i<n; i++)
{
scanf("%s",s);
ac.insert(s);
}
ac.build();
Matrix a=ac.get_mat();
a=pow_M(a,m);
ull res=0;
for(int i=0; i<a.n; i++)
res+=a.mat[0][i];
res--;
a=Matrix(2);
a.mat[0][0]=26,a.mat[1][0]=a.mat[1][1]=1;
a=pow_M(a,m);
ull ans=a.mat[0][0]+a.mat[1][0]-1;
ans-=res;
printf("%llu\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: