您的位置:首页 > 其它

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

2017-08-27 11:33 453 查看
http://acm.hdu.edu.cn/showproblem.php?pid=2243

题意:

给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数。

思路:

如果做过poj2778的话,那么这题相对来说就会容易一些。

如果直接去计算的话,情况很复杂,和poj2778一样,我们先求出不包含模式串的个数,最后只需要相减就可以。

因为这道题目长度只要不超过n就可以,所以在构造矩阵的时候需要多加一列,该列值每行全设为1(这样最后一列的值就是对上一个矩阵每一行的和,完美计算了了各种长度的个数之和)。最后得到的值res-1就是不包含的情况个数(减去1是因为一开始的时候多算了1)。

接下来计算一下所有情况的个数,$f(n)=1+26^1+26^2+...+26^n$,可以得出$f(n)=26*f(n-1)+1$,于是这就能构造出一个矩阵了,最后得到的res-1就是所有的情况个数。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=10000+5;

int n, m, num;
char s[20];

struct Trie
{
int son[30];
int cnt;
int fail;
}t[100];

struct Matrix
{
unsigned long long mat[40][40], n;
Matrix(){}
Matrix(int _n)
{
n=_n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mat[i][j]=0;
}
Matrix operator*(const Matrix& b) const
{
Matrix c=Matrix(n);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
c.mat[i][j]+=mat[i][k]*b.mat[k][j];
}
}
}
return c;
}
};

void init(int x)
{
t[x].fail=0;
t[x].cnt=0;
memset(t[x].son,0,sizeof(t[x].son));
}

void trie(char *s)
{
int n=strlen(s);
int x=0;
for(int i=0;i<n;i++)
{
int c=s[i]-'a'+1;
if(!t[x].son[c])
{
num++;
init(num);
t[x].son[c]=num;
}
x=t[x].son[c];
}
t[x].cnt=1;
}

void buildAC()
{
queue<int> Q;
for(int i=1;i<=26;i++)  if(t[0].son[i])  Q.push(t[0].son[i]);
while(!Q.empty())
{
int x=Q.front(); Q.pop();
int fail=t[x].fail;
for(int i=1;i<=26;i++)
{

int y=t[x].son[i];
if(y)
{
t[y].fail=t[fail].son[i];
t[y].cnt|=t[t[fail].son[i]].cnt;  //这儿很重要,这个标记需要传递
Q.push(y);
}
else t[x].son[i]=t[fail].son[i];
}
}
}

Matrix getMatrix()
{
Matrix c=Matrix(num+2);
for(int i=0;i<=num;i++)
{
for(int j=1;j<=26;j++)
{
if(t[t[i].son[j]].cnt==0)  c.mat[i][t[i].son[j]]++;
}
}
for(int i=0; i<num+2; i++)  c.mat[i][num+1]=1;
return c;
}

Matrix q_pow(Matrix base, int n)
{
Matrix ans=Matrix(base.n);
for(int i=0;i<ans.n;i++)   ans.mat[i][i]=1;
while(n)
{
if(n&1)  ans=ans*base;
base=base*base;
n>>=1;
}
return ans;
}

int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&m,&n))
{
init(0);
num=0;
for(int i=1;i<=m;i++)
{
scanf("%s",s);
trie(s);
}
buildAC();
Matrix c=getMatrix();
c = q_pow(c,n);
unsigned long long res = 0;
for(int i=0;i<c.n;i++) res+=c.mat[0][i];
res--;
c=Matrix(2);
c.mat[0][0]=26;
c.mat[0][1]=c.mat[1][1]=1;
c=q_pow(c,n);
unsigned long long ans=c.mat[0][0]+c.mat[0][1];
ans--;
ans-=res;
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: