【刷題】BZOJ 1030 [JSOI2007]文本生成器
阿新 • • 發佈:2018-07-12
line 存在 就是 for pty include 讀文本 只需要 std
註意的是,在求fail的時候,類似於求last,如果這個節點通過fail樹能到達的節點是一個串的結尾,那麽這個節點代表的串的後綴一定包含了一個串,這樣也是不能轉移的,所以要把這個點的fail的狀態考慮進來
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個字母,如果是一個串的結尾,那麽肯定不行,否則走到下一個點,貢獻加上
#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]文本生成器