spoj 1676 Text Generator ac机+矩阵幂 好题!

SPOJ Problem Set (classical)

1676. Text Generator

Problem code: GEN

LoadingTime has been given a task these days. He is required to write a tool called Text Generator. This software is widely used among the kids who are under seven. It generates an article with the size of a given number L for users. If an article contains at least one word which the users know, we consider it readable. Now, LoadingTime wants to know, how many readable articles can it generates, and he can improve his Text Generator. Could you help him??

Input

The input contains multiple test cases.

The first line of each test case contains two integer N (1 <= N <= 10), L (1 <= L <= 1000000). The following N lines contain N words representing the words knew by the users. All the words and the generated article only contain uppercase letters, and the length of each word is not greater than 6.

Output

For each test case, your program should output a integer as LoadingTime required. As the number could be quite large, you only need to print the answer modulo 10007.

Example

Input:
2 2
A
B
2 10000
ABC
B

Output:
100
5960


Added by:Bin Jin
Date:2007-07-05
Time limit:10s
Source limit:50000B
Memory limit:256MB
Cluster:Pyramid (Intel Pentium III 733 MHz)
Languages:All except: C++ 4.0.0-8
Resource: 









题目给定n个熟悉的串,问长度为m且至少含一个熟悉串的方案数,m<=100万。逆向思维,用总的方案数减去不含熟悉串的方案数。

思路:先用ac自动机求出初始矩阵,初始矩阵A.matrix[i][j]表示从自动机的节点i走一步不经过熟悉串的结尾有几种方法可以走到节点j,然后用对A.matrix矩阵进行二分快速幂求A^L,其中A.matrix[i][j]表示从i到j经过L步不经过熟悉串的结尾的方法数。幂乘的时候注意尽量少用%mod。(当超过mod时才用%mod,详见代码),最后用26^L-sum(A.matrix[0][k],0<=k<sz),其中sz为ac机上的节点个数,但这样会T = =。我们又注意到对于自动机节点i来说,如果它的cnt!=0,那么它并没有存在的意义。所以我们对ac机上cnt=0的点进行重新编码,建立初始矩阵,最后用26^L-sum(A.matrix[0][k],0<=k<sz'),sz'为ac机上cnt=0的个数。(详见程序)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=65;
const int sigma_size=26;
const int mod=10007;
int n,m,l,sz,head,tail;
struct node
{
    int cnt,id;
    node *next[sigma_size],*fail;
}trie[MAXN],*root,*que[MAXN];
struct AC
{
    node *createnode()
    {
        for(int k=0;k<sigma_size;k++)
            trie[sz].next[k]=NULL;
        trie[sz].fail=NULL;
        trie[sz].cnt=0,trie[sz].id=sz;
        return &trie[sz++];
    }
    void init()
    {
        sz=0;
        head=tail=0;
        root=createnode();
    }
    void insert(char *str)
    {
        node *p=root;
        int len=strlen(str);
        for(int i=0;i<len;i++)
        {
            int k=str[i]-'A';
            if(p->next[k]==NULL)
                p->next[k]=createnode();
            p=p->next[k];
        }
        p->cnt++;
    }
    void get_fail()
    {
        que[tail++]=root;
        while(head<tail)
        {
            node *p=que[head++];
            for(int k=0;k<sigma_size;k++)
                if(p->next[k])
                {
                    if(p==root)
                        p->next[k]->fail=root;
                    else
                        p->next[k]->fail=p->fail->next[k];
                    p->next[k]->cnt|=p->next[k]->fail->cnt;
                    que[tail++]=p->next[k];
                }
                else
                {
                    if(p==root)
                        p->next[k]=root;
                    else
                        p->next[k]=p->fail->next[k];
                }
        }
    }
}ac;
struct Matrix
{
    int matrix[MAXN][MAXN];
}E;
Matrix matrix_mul(Matrix a,Matrix b)
{
    Matrix c;
    for(int i=0;i<m;i++)
        for(int j=0;j<m;j++)
        {
            c.matrix[i][j]=0;
            for(int k=0;k<m;k++)
                if(a.matrix[i][k] && b.matrix[k][j])
                {
                    c.matrix[i][j]+=a.matrix[i][k]*b.matrix[k][j];
                    if(c.matrix[i][j]>=mod)
                        c.matrix[i][j]%=mod;
                }
        }
    return c;
}
Matrix matrix_pow(Matrix a,int k)
{
    Matrix c=E;
    while(k)
    {
        if(k&1)
            c=matrix_mul(c,a);
        a=matrix_mul(a,a);
        k>>=1;
    }
    return c;
}
int num_pow(int a,int k)
{
    int ans=1;
    while(k)
    {
        if(k&1)
        {
            ans*=a;
            if(ans>=mod)
                ans%=mod;
        }
        a=a*a; k>>=1;
        if(a>=mod)
            a%=mod;
    }
    return ans;
}
int main()
{
    //freopen("text.txt","r",stdin);
    for(int i=0;i<MAXN;i++)
        E.matrix[i][i]=1;
    while(~scanf("%d%d",&n,&l))
    {
        ac.init();
        char str[10];
        for(int i=0;i<n;i++)
        {
            scanf("%s",str);
            ac.insert(str);
        }
        ac.get_fail();
        Matrix A;
        int u=0,v,num;
        for(int i=0;i<sz;i++)
        if(!trie[i].cnt)
        {
            v=0;
            for(int j=0;j<sz;j++)
                if(!trie[j].cnt)
                {
                    num=0;
                    for(int k=0;k<sigma_size;k++)
                        if(trie[i].next[k]->id==trie[j].id)
                            num++;
                    A.matrix[u][v]=num;
                    v++;
                }
            u++;
        }
        m=u;
        int ans=num_pow(26,l);
        A=matrix_pow(A,l);
        int temp=0;
        for(int i=0;i<m;i++)
        {
            temp=(temp+A.matrix[0][i]);
            if(temp>=mod)
                temp%=mod;
        }
        ans-=temp;
        if(ans<0)
            ans+=mod;
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值