HDU2243_考研路茫茫――单词情结
给出一些词根,问你有多少种长度为L的串包含至少一个词根。
去年就在敲这个题了,今年才敲出来,还是内牛满面之中。。。
要求包含至少一个的情况,需要求出所有的情况,减去一个都没有的情况就可以了。
对于给出的词根,上自动机。然后我们根据tire图可以得出关系状态转移的矩阵。
显然就是矩阵求和了,通过二分幂解决即可。这些地方都有一些技巧可言的。
一开始没有考虑压缩fail指针,考虑了非法的情况,真是wa出翔了。
召唤代码君:
#include <iostream> #include <cstring> #include <cstdio> #include <queue> typedef unsigned long long ll; using namespace std; ll n,L; ll next[55][26],fail[55],tag[55],N; struct Mat{ ll a[55][55]; Mat() { memset(a,0,sizeof a); } Mat operator + (Mat M) const { Mat tmp; for (ll i=0; i<=n; i++) for (ll j=0; j<=n; j++) tmp.a[i][j]=a[i][j]+M.a[i][j]; return tmp; } Mat operator * (Mat M) const { Mat tmp; for (ll i=0; i<=n; i++) for (ll j=0; j<=n; j++) for (ll k=0; k<=n; k++) tmp.a[i][j]+=a[i][k]*M.a[k][j]; return tmp; } Mat power(ll x) { Mat tmp1,tmp2; for (ll i=0; i<=n; i++){ tmp1.a[i][i]=1; for (ll j=0; j<=n; j++){ tmp2.a[i][j]=a[i][j]; } } while (x){ if (x&1) tmp1=tmp1*tmp2; x>>=1,tmp2=tmp2*tmp2; } return tmp1; } void output(){ for (ll i=0; i<=n; i++){ for (ll j=0; j<=n; j++) cout<<a[i][j]<<' '; cout<<endl; } } }; ll add() { fail[++N]=0,tag[N]=0; for (ll i=0; i<26; i++) next[N][i]=0; return N; } void insert(char s[]) { ll cur=0,k; for (ll i=0; s[i]; i++){ k=s[i]-'a'; if (!next[cur][k]) next[cur][k]=add(); cur=next[cur][k]; } tag[cur]=1; } void AC_build() { queue<int> Q; Q.push(0); while (!Q.empty()){ ll cur=Q.front(),child,k; Q.pop(); for (ll i=0; i<26; i++){ child=next[cur][i]; if (child){ if (!cur) fail[child]=0; else{ for (k=fail[cur]; k && !next[k][i]; k=fail[k]) ; fail[child]=next[k][i]; } Q.push(child); } else next[cur][i]=next[fail[cur]][i]; } } } ll power(ll x,ll y) { ll tot=1; while (y){ if (y&1) tot=tot*x; y>>=1,x=x*x; } return tot; } int main() { char s[55]; while (cin>>n>>L){ N=0; fail[0]=tag[0]=0; for (ll i=0; i<26; i++) next[0][i]=0; for (ll i=0; i<n; i++) { scanf("%s",s); insert(s); } AC_build(); for (ll i=0; i<=N; i++) if (tag[fail[i]]) tag[i]=1; n=N; Mat cur,E,ans; for (ll i=0; i<=n; i++) for (ll j=0; j<26; j++){ if (!tag[i] && !tag[next[i][j]]) cur.a[i][next[i][j]]++; } for (ll i=0; i<=n; i++) E.a[i][i]=1; Mat tmp=E; ll num=0,here=1; while (L>0){ if (L&1) { ans=ans+tmp*cur.power(L); num+=here*power(26,L); } L>>=1; here=here*power(26,L)+here; tmp=tmp*(cur.power(L)+E); } for(ll i=0; i<=n; i++) num-=ans.a[0][i]; cout<<num<<endl; } return 0; }
如有转载,请注明出处(http://www.cnblogs.com/lochan)