zoukankan      html  css  js  c++  java
  • hdu2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2243

    题目大意:

      给出n个单词,问存在多少长度小于l的字符串,子串不含任意一个单词,答案对$2^{64}$取模。

      细节多如牛毛的一道题,可以看成是poj2778升级版,长度为定值l的做法,见https://www.cnblogs.com/FZUzyz/p/12885877.html,只是将字母数量从4个推广到了26个而已,没有别的变化。然后是这个坑爹模数,2的64次方,刚开始上了int128,因为两个乘起来的话long long绝对爆了,后面看了部分题解,发现直接开unsigned long long即可,因为ull就是64位,也不需要取模,自然溢出的结果就是他的答案,很巧妙有木有。

      随后的思路和poj2778一样,求出合法数量,总数量减去非法数量即可。先求总数量,对于长度小于l的,其数量应该为$sum_{i=1}^{l}26^{i}$,很明显是个等比数列求和公式对吧,是不是很心动,想用等比数列求和公式$sum=frac{26(26^{l}-1)}{25}$,没错,我就这么写的,然后样例都跑不出来,因为有除法,需要求逆元,而模数$2^{64}$又不是质数!所以另求他法,假设f(n)为长度为1-n的串数量总和,不难发现$f(n)=26f(n-1)+26$,这个式子很明显就可以用矩阵快速幂求了。那么总数量的问题就解决了。接下来求合法数量了,要求小于l的总和,显然是要求出$sum_{i=1}^{l}sum_{j=1}^{size}mat[0][j]$,mat为路径矩阵形式,size为矩阵大小。可以构造矩阵

    egin{pmatrix}
    mat & 1\
    0 & 1
    end{pmatrix}

    注意改造后的矩阵mat2大小为mat矩阵大小+1,将其右侧全部改为1,下方改为0(右下为1除外),这样一来,$mat2^{l}$就变成了

    egin{pmatrix}
    mat^{l} & sum_{i=1}^{l-1}sum_{j=1}^{size}mat[0][j]\
    0 & 1
    end{pmatrix}

    证明很容易,数学归纳法或者别的方法都可以证明。所以最后只需要将$mat2^{l}$第首行元素求和即可。

    最后贴上AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <ll,ll> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define all(x) x.begin(),x.end()
    #define pb push_back
    #define fi first
    #define se second
    #define mes(a,b) memset(a,b,sizeof a)
    #define mp make_pair
    #define dd(x) cout<<#x<<"="<<x<<" "
    #define de(x) cout<<#x<<"="<<x<<"
    "
    #define debug() cout<<"I love Miyamizu Mitsuha forever.
    "
    const int inf=0x3f3f3f3f;
    const int maxn=105;
    
    
    class matrix
    {
        public:
            ull arrcy[35][35];
            int row,column;
            matrix()
            {
                memset(arrcy,0,sizeof arrcy);
                column=row=0;
            }
            friend matrix operator *(matrix s1,matrix s2)
            {
                int i,j;
                matrix s3;
                for (i=0;i<s1.row;i++)
                {
                    for (j=0;j<s2.column;j++)
                    {
                        for (int k=0;k<s1.column;k++)
                        {
                            s3.arrcy[i][j]+=s1.arrcy[i][k]*s2.arrcy[k][j];
                        }
                    }
                }
                s3.row=s1.row;
                s3.column=s2.column;
                return s3;
            }
            void show()
            {
                for(int i=0;i<row;i++)
                {
                    for (int j=0;j<column;j++)
                        cout<<arrcy[i][j]<<" ";
                    cout<<endl;
                }
            }
    }mat,mul;
    matrix quick_pow(matrix s1,long long n)
    {
        matrix mul=s1,ans;
        ans.row=ans.column=s1.row;
        memset(ans.arrcy,0,sizeof ans.arrcy);
        for(int i=0;i<ans.row;i++)
            ans.arrcy[i][i]=1;
        while(n)
        {
            if(n&1) ans=ans*mul;
            mul=mul*mul;
            n>>=1;
        }
        return ans;
    }
    
    ull qpow(ull a,ull b)
    {
        ull ans=1;
        for(;b;b>>=1,a=a*a)
            if(b&1) ans*=a;
        return ans;
    }
    class Trie
    {
        public:
            Trie()
            {
                cnt=1;
            }
            int cnt;
            int trie[maxn][26];
            int fail[maxn];
            bool bad[maxn];
            void init()
            {
                rep(i,0,cnt)
                {
                    fail[i]=bad[i]=0;
                    rep(j,0,26) trie[i][j]=0;
                }
                cnt=1;
            }
            void insert(string s)
            {
                int len=s.size();
                int pos=0;
                rep(i,0,len)
                {
                    int next=s[i]-'a';
                    if(!trie[pos][next]) trie[pos][next]=cnt++;
                    pos=trie[pos][next];
                }
                bad[pos]=1;
            }
            void getfail()
            {
                queue<int> q;
                rep(i,0,26)
                {
                    if(trie[0][i])
                    {
                        fail[trie[0][i]]=0;
                        q.push(trie[0][i]);
                    }
                }
                while(!q.empty())
                {
                    int pos=q.front();
                    q.pop();
                    rep(i,0,26)
                    {
                        bad[pos]|=bad[fail[pos]];
                        if(trie[pos][i])
                        {
                            fail[trie[pos][i]]=trie[fail[pos]][i];
                            q.push(trie[pos][i]);
                        }
                        else trie[pos][i]=trie[fail[pos]][i];
                    }
                }
            }
    }ac;
    string s;
    ull cal(ll x)
    {
        matrix l,r;
        r.row=2;r.column=1;
        r.arrcy[0][0]=0;
        r.arrcy[1][0]=1;
        l.row=l.column=2;
        l.arrcy[0][0]=l.arrcy[0][1]=26;
        l.arrcy[1][0]=0;l.arrcy[1][1]=1;
        r=quick_pow(l,x)*r;
        return r.arrcy[0][0];
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,l;
        while(cin>>n>>l)
        {
            ac.init();
            mes(mul.arrcy,0);mes(mat.arrcy,0);
            rep(i,0,n)
            {
                cin>>s;
                ac.insert(s);
            }
            ac.getfail();
            mat.row=1;
            mat.column=ac.cnt+1;
            mat.arrcy[0][0]=1;
            mul.row=mul.column=ac.cnt+1;
            rep(i,0,ac.cnt)
            {
                if(ac.bad[i]) continue;
                rep(j,0,26)
                {
                    if(!ac.bad[ac.trie[i][j]]) mul.arrcy[i][ac.trie[i][j]]++;
                }
            }
            rep(i,0,mul.column) mul.arrcy[i][mul.column-1]=1;
            mat=mat*quick_pow(mul,l);
            ull ans=0;
            rep(i,0,mat.column) ans=(ans+mat.arrcy[0][i]);
            ans--;
            ull cnt=cal(l);
            cnt-=ans;
            cout<<cnt<<"
    ";
        }
        return 0;
    }
  • 相关阅读:
    composer安装Workerman报错:Installation failed, reverting ./composer.json to its original content.
    从零开始搭建linux下laravel 5.5所需环境(三)
    ASPNET Razor 使用 @Ajax.BeginForm 需要注意到的细节
    .NET跨平台
    1172金币
    1044电子表
    1358统计号码牌
    1355疫情防控 数据调查
    1056反向输出一个三位数2
    1071行李托运
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/12885975.html
Copyright © 2011-2022 走看看