hdu 2243 考研路茫茫——单词情结 (ac自动机+矩阵优化)

题意:

这题简直是个奇葩的题目。题目各处n个串,然后要求长度小与等于n且包含着n个串至少一个串的串的个数。

题解:

首先我们构造一个字典图节点个数的矩阵,这样可以求出长度等于L不包含n个串的个数,那么把之前的矩阵看成一个部分,这样求  { f[n] , 1 } = { f[n-1] , 1 } *{ 原矩阵 0 ; 1 1 }

这样就可以求出不包含且小于等于的个数,然后用总数-这个就得出了答案。

不过一直wa,找了一个下午都没找出来。


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef __int64 ll;
typedef unsigned __int64 Ull;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const Ull MOD=1000000;
const int maxn=1005;
const int SIZE=35;
const int type=26;
char str[8];

struct Matrix
{
    Ull maze[SIZE][SIZE],n;
    Matrix(){}
    Matrix(int _n)
    {
        n = _n;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                maze[i][j]=0;
    }
    Matrix operator *(const Matrix &a)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.maze[i][j]+=maze[i][k]*a.maze[k][j];
        return ret;
    }

    Matrix operator^(Ull k)
    {
        Matrix ans(this->n);
        Matrix a=*this;
        for(int i=0;i<n;i++) ans.maze[i][i]=1;
        while(k)
        {
            if(k&1)
                ans=ans*a;
            a=a*a;
            k>>=1;
        }
        return ans;
    }

};

Ull pow26(Ull k)
{
    Ull a=26;
    Ull ans=1;
    while(k)
    {
        if(k&1)
            ans=ans*a;
        a=a*a;
        k>>=1;
    }
    return ans;
}

struct ACautomaton
{
    int next[SIZE][type],fail[SIZE],word[SIZE];
    int cnt,root;

    int newNode()
    {
        for(int i=0;i<type;i++)
            next[cnt][i]=-1;
        word[cnt++]=0;
        return cnt-1;
    }

    void Init()
    {
        cnt=0;
        root=newNode();
    }

    void Insert(char buff[])
    {
        int now=root;
        int len=strlen(buff);
        for(int i=0,k;i<len;i++)
        {
            k=buff[i]-'a';
            if(next[now][k]==-1)
                next[now][k]=newNode();
            now=next[now][k];
        }
        word[now]=1;
    }

    void build()
    {
        fail[root]=root;
        int now=root;
        queue<int>Q;
        for(int i=0;i<type;i++)
        {
            if(next[now][i]==-1)
                next[now][i]=root;
            else
            {
                fail[next[now][i]]=root;
                Q.push(next[now][i]);
            }
        }
        while(!Q.empty())
        {
            now=Q.front();
            Q.pop();
            if(word[fail[now]]==1) word[now]=1;
            for(int i=0;i<type;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]);
                }
            }
        }
    }

    Ull solve(Ull L)
    {
        Matrix a(cnt+1);
        for(int i=0;i<cnt;i++)
            for(int j=0;j<type;j++)
            {
                int k=next[i][j];
                if(!word[k])
                    a.maze[i][k]++;
            }
        for(int i=0;i<a.n;i++)
            a.maze[i][cnt]=1;///这里多加一维 是吧原来矩阵看成一部分然后和左边的1构成一个新矩阵这样就能求小于等于长度的所有路径数
        a=a^L;
        Ull ans=0;
        for(int i=0;i<a.n;i++)
            ans+=a.maze[0][i];
        Ull sum=0;
        sum=26*(pow26(L)-1)/25+1;///等比数列前n项和
        return sum-ans;
    }

}ac;

int main()
{
    int N;
    Ull L;
    while(scanf("%d %I64u",&N,&L)!=EOF)
    {
        ac.Init();
        for(int i=1;i<=N;i++)
        {
            scanf("%s",str);
            ac.Insert(str);
        }
        ac.build();
        printf("%I64u\n",ac.solve(L));
    }
    return 0;
}




你可能感兴趣的:(hdu 2243 考研路茫茫——单词情结 (ac自动机+矩阵优化))