hdu 2243 AC自动机+dp(矩阵快速幂优化)

做这个之前建议做一下poj 2778
这道题要求长度小于等于m的字符串包含所给串的有多少种,可以算出所有的情况然后减去不包含所给串的情况就是所求的。
大佬博客
大佬博客
矩阵里面存的是从i节点到j节点走一步共有多少种走法(不能走题目上给的字符串)。
然后将这个矩阵m次幂就可以求出走m步(长度为m的字符串)有多少种不包含做给串的字符串。小于等于m将其各个次幂加起来就好了,可以改一改矩阵一次就可以算出来。
所有情况就是26的1到m次幂加起来。

#include
#include
#include
#include
#include
#define LL unsigned long long
using namespace std;
const int maxn=1e6+10;
struct zp
{
    LL arr[110][110];//代表从i节点走一步到j节点有多少种走法
} x;
int zlen;
zp jx(zp a,zp b)
{
    zp res;
    for(int i=0; ifor(int j=0; j0;
    for(int i=0; ifor(int j=0; jfor(int k=0; kreturn res;
}
zp jk(zp a,int b)
{
    zp res;
    for(int i=0; ifor(int j=0; jwhile(b)
    {
        if(b&1)
            res=jx(res,a);
        a=jx(a,a);
        b>>=1;
    }
    return res;
}
struct AC
{
    int node[maxn][26];
    int fail[maxn],cont,root,flag[maxn];
    int newnode()
    {
        for(int i=0; i<26; i++)
            node[cont][i]=-1;
        flag[cont++]=0;
        return cont-1;
    }
    void init()
    {
        cont=0;
        root=newnode();
    }
    void build(char a[])
    {
        int len=strlen(a);
        int now=root;
        for(int i=0; iif(node[now][a[i]-'a']==-1)
                node[now][a[i]-'a']=newnode();
            now=node[now][a[i]-'a'];
        }
        flag[now]=1;
    }
    void get_fail()
    {
        queue<int> q;
        fail[root]=root;
        for(int i=0; i<26; i++)
        {
            if(node[root][i]==-1)
            {
                node[root][i]=root;
            }
            else
            {
                fail[node[root][i]]=root;
                q.push(node[root][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=0; i<26; i++)
            {
                if(node[now][i]==-1)
                {
                    node[now][i]=node[fail[now]][i];
                    if(flag[fail[node[now][i]]]==1)//当当前节点的fail指向一个单词结尾时这个单词也是不可到达的
                        flag[node[now][i]]=1;
                }
                else
                {
                    fail[node[now][i]]=node[fail[now]][i];
                    q.push(node[now][i]);
                    if(flag[fail[node[now][i]]]==1)
                        flag[node[now][i]]=1;
                }
            }
        }
    }
    void buildMatrix()
    {
        memset(x.arr,0,sizeof(x.arr));
        for(int i=0; ifor(int j=0; j<26; j++)
                if(flag[node[i][j]]!=1&&flag[fail[node[i][j]]]!=1)
                    x.arr[i][node[i][j]]++;//这里加加是因为从同一个节点出发走一步可能有好几种走法
                    for(int i=0;i1;i++)//要求矩阵x的一到m次幂所以要在后面加一列
                        x.arr[i][cont]=1;
    }
};
AC ac;
char s[2010];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        ac.init();
        for(int i=0; iscanf("%s",s);
            ac.build(s);
        }
        ac.get_fail();
        ac.buildMatrix();
        zlen=ac.cont+1;
        x=jk(x,m);
        LL ans=0;
        for(int i=0;i0][i];
        x.arr[0][0]=26,x.arr[0][1]=1;//矩阵求26^1+26^2......26
        x.arr[1][0]=0,x.arr[1][1]=1;
        zlen=2;
        x=jk(x,m);
        ans=x.arr[0][0]+x.arr[0][1]-ans;
        printf("%llu\n",ans);
    }
}

你可能感兴趣的:(字符串,矩阵快速幂)