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;
}

 

posted @ 2014-07-26 23:09  092000  阅读(612)  评论(0编辑  收藏  举报