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

题意:给你n个字符串,和长度m,问你长度<=m的字符串中,包括这n个字符串的有多少个

解题思路:这题和poj2778差不多,但是那道题求的是不包含的,所有我们换个角度,求出所有的可能性减去不包括的就是了,但这道题有一个和那道题不一样的地方就是,他是<=长度len的所有,所有需要构造矩阵的时候加一列全为1的元素,然后求所有可能性也需要这样,构造一个2x2的矩阵【26 1 0 1】的矩阵,因为是对2^64取模,所以直接开unsigned long long 就行了

代码

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
typedef unsigned long long ll;
const int N=50;
const int maxn=110;
ll m;
int tot,n,cnt;
int fail[N];
int trie[N][26];
int visit[N];
char t[10];
struct Matrix
{
    ll m[maxn][maxn];
    Matrix()
    {
        memset(m,0,sizeof(m));
    }
    void init()
    {
        for(int i=0; i<=cnt; i++)
            for(int j=0; j<=cnt; j++)
                m[i][j]=(i==j);
    }
    Matrix  operator +(const Matrix &b)const
    {
        Matrix c;
        for(int i=0; i<=cnt; i++)
        {
            for(int j=0; j<=cnt; j++)
            {
                c.m[i][j]=(m[i][j]+b.m[i][j]);
            }
        }
        return c;
    }
    Matrix  operator *(const Matrix &b)const
    {
        Matrix c;
        for(int i=0; i<=cnt; i++)
        {
            for(int j=0; j<=cnt; j++)
            {
                for(int k=0; k<=cnt; k++)
                {
                    c.m[i][j]=(c.m[i][j]+(m[i][k]*b.m[k][j]));
                }
            }
        }
        return c;
    }
    Matrix  operator^(const ll &t)const
    {
        Matrix ans,a=(*this);
        ans.init();
        ll n=t;
        while(n)
        {
            if(n&1) ans=ans*a;
            a=a*a;
            n>>=1;
        }
        return ans;
    }
};
void build_trie(char *str)
{
    int root=0;
    int slen=strlen(str);
    for(int i=0;i<slen;i++)
    {
        int id=str[i]-'a';
        if(!trie[root][id])
            trie[root][id]=++tot;
        root=trie[root][id];
    }
    visit[root]=1;
}
void build_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i]!=0)
            q.push(trie[0][i]);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        if(visit[fail[now]])
            visit[now]=1;
        for(int i=0;i<26;i++)
        {
            if(!trie[now][i])
            {
                trie[now][i]=trie[fail[now]][i];
                continue;
            }
            fail[trie[now][i]]=trie[fail[now]][i];
            q.push(trie[now][i]);
        }
    }
}
void init()
{
    memset(trie,0,sizeof(trie));
    memset(fail,0,sizeof(fail));
    memset(visit,0,sizeof(visit));
    tot=0;
}
int main()
{
    while(scanf("%d%u",&n,&m)!=EOF)
    {
        Matrix a,b;init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",t);build_trie(t);
        }
        build_fail();
        for(int i=0;i<=tot;i++)
        {
            if(visit[i])continue;
            for(int j=0;j<26;j++)
            {
                if(visit[trie[i][j]])continue;
                a.m[i][trie[i][j]]++;
            }
        }
        for(int i=0;i<=tot+1;i++)
            a.m[i][tot+1]=1;
        cnt=tot+1;
        a=a^m; ll ans=0;
        for(int i=0;i<=cnt;i++)
            ans+=a.m[0][i];
        cnt=2;
        b.m[0][0]=26;b.m[0][1]=1;b.m[1][1]=1;
        b=b^m;
        ll tmp=b.m[0][0]+b.m[0][1];
       cout<<tmp-ans<<endl;
    }
}

 

posted @ 2019-05-04 22:24  荒岛的龟  阅读(368)  评论(0编辑  收藏  举报