1. 程式人生 > >【刷題】BZOJ 1030 [JSOI2007]文本生成器

【刷題】BZOJ 1030 [JSOI2007]文本生成器

line 存在 就是 for pty include 讀文本 只需要 std

Description

  JSOI交給隊員ZYX一個任務,編制一個稱之為“文本生成器”的電腦軟件:該軟件的使用者是一些低幼人群,他們現在使用的是GW文本生成器v6版。該軟件可以隨機生成一些文章―――總是生成一篇長度固定且完全隨機的文章—— 也就是說,生成的文章中每個字節都是完全隨機的。如果一篇文章中至少包含使用者們了解的一個單詞,那麽我們說這篇文章是可讀的(我們稱文章a包含單詞b,當且僅當單詞b是文章a的子串)。但是,即使按照這樣的標準,使用者現在使用的GW文本生成器v6版所生成的文章也是幾乎完全不可讀的?。ZYX需要指出GW文本生成器 v6生成的所有文本中可讀文本的數量,以便能夠成功獲得v7更新版。你能幫助他嗎?

Input

  輸入文件的第一行包含兩個正整數,分別是使用者了解的單詞總數N (<= 60),GW文本生成器 v6生成的文本固定長度M;以下N行,每一行包含一個使用者了解的單詞。這裏所有單詞及文本的長度不會超過100,並且只可能包含英文大寫字母A..Z

Output

  一個整數,表示可能的文章總數。只需要知道結果模10007的值。

Sample Input

2 2
A
B

Sample Output

100

Solution

在AC自動機上dp
把給出的串插入AC自動機,設 \(f[i][j]\) 表示現在在AC自動機上的 \(i\) 號節點,已經構造了要求的串的前 \(j\) 位的方案數
每次轉移,枚舉前一位可能存在的位置,再枚舉26個字母,如果是一個串的結尾,那麽肯定不行,否則走到下一個點,貢獻加上

註意的是,在求fail的時候,類似於求last,如果這個節點通過fail樹能到達的節點是一個串的結尾,那麽這個節點代表的串的後綴一定包含了一個串,這樣也是不能轉移的,所以要把這個點的fail的狀態考慮進來

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=60+10,MAXM=100+10,MAXS=6000+10,Mod=1e4+7;
int n,m,ch[MAXS][30],fail[MAXS],last[MAXS],cnt,ed[MAXS];
ll f[MAXS][MAXM],ans;
char s[MAXM];
std::queue<int> q;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void init()
{
    for(register int i=0,lt=strlen(s);i<lt;++i)s[i]-='A'-1;
}
inline void insert()
{
    int x=1;
    for(register int i=0,lt=strlen(s);i<lt;++i)
    {
        if(!ch[x][s[i]])x=ch[x][s[i]]=++cnt;
        else x=ch[x][s[i]];
    }
    ed[x]=1;
}
inline void getfail()
{
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(register int i=1,y,z;i<=26;++i)
            if(ch[x][i])
            {
                y=ch[x][i],z=fail[x];
                while(z&&!ch[z][i])z=fail[z];
                fail[y]=ch[z][i],chkmax(ed[y],ed[fail[y]]);
                q.push(y);
            }
    }
}
inline ll qexp(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)res=res*a%Mod;
        a=a*a%Mod;
        b>>=1;
    }
    return res;
}
int main()
{
    read(n);read(m);
    for(register int i=1;i<=26;++i)ch[0][i]=1;cnt=1;
    for(register int i=1;i<=n;++i)scanf("%s",s),init(),insert();
    getfail();
    f[1][0]=1;
    for(register int j=1;j<=m;++j)
        for(register int i=1;i<=cnt;++i)
            if(!ed[i]&&f[i][j-1])
                for(register int k=1;k<=26;++k)
                {
                    int p=i;
                    while(!ch[p][k])p=fail[p];
                    (f[ch[p][k]][j]+=f[i][j-1])%=Mod;
                }
    for(register int i=1;i<=cnt;++i)
        if(!ed[i])(ans+=f[i][m])%=Mod;
    write((qexp(26,m)-ans+Mod)%Mod,'\n');
    return 0;
}

【刷題】BZOJ 1030 [JSOI2007]文本生成器