HDU - 2604 Queuing DFA + 矩阵二分

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2604

http://vjudge.net/problem/viewProblem.action?id=17436


1.题意:

求长度为L的不包含fmf、fff这样的字串的字符串有多少个。

2.题解

(1)要知道DFA(有限自动机)的基础知识;

(2)求禁止位(fmf,fff)为长度为三的字符串,我们常用两个字符表示一个状态,所以对于长度小于3的字符串要特判一下;

(3)两个字符一个状态就可以得到一个DFA,这个DFA有4个状态,当然这不是一个严谨的DFA,只是我们做题意义上的DFA。这个DFA,每个状态都是初态,每个状态也都是终态,但是严格意义上的DFA初态只有一个。对于状态转移矩阵就参照代码里的吧,g[i][j]表示状态i到状态j有几种转移方式。初始状态表示长度为2末尾状态为i的串转移到长度为3末尾状态为j的串的路径数。那么只要对于g[][]求n-2次幂,就可以扩展到求长度为2末尾状态为i的串转移到长度为n末尾状态为j的串的路径数。

(4)求幂结束后统计路径总数

code:


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define Clr(x) memset(x,0,sizeof x)
#define sz 4
int MOD;
int mem[3]={0,2,4};
int m[sz][sz]={{
    1,1,0,0},{//mm
    0,0,1,1},{//mf
    1,0,0,0},{//fm
    0,0,1,0}//ff
};
struct Mat{
    int x[sz][sz];
    Mat(){Clr(x);}
    Mat(int n){
        Clr(x);
        for(int i=0;i<sz;i++)x[i][i]=n;
    }
    void init(){
        memcpy(x,m,sizeof m);
    }
    int getAns(){
        int ans=0;
        for(int i=0;i<sz;i++)
        for(int j=0;j<sz;j++)
            ans+=x[i][j];
        return ans%MOD;
    }
    void print(){
        for(int i=0;i<sz;i++){
            for(int j=0;j<sz;j++)
                printf("%d ",x[i][j]);
            puts("");
        }
        puts("");
    }
};
Mat operator*(Mat a,Mat b){
    Mat s;
    for(int i=0;i<sz;i++)
    for(int j=0;j<sz;j++){
        if(a.x[i][j]==0) continue;
        for(int k=0;k<sz;k++)
            s.x[i][k]=(s.x[i][k]+a.x[i][j]*b.x[j][k])%MOD;
    }
    return s;
}
Mat operator^(Mat a,int b){
    Mat s(1);
    for(;b;b>>=1){
        if(b&1)s=s*a;
        a=a*a;
    }
    return s;
}
int main()
{
    int L,ans;
    while(scanf("%d%d",&L,&MOD)==2){
        if(L<3){
            ans=mem[L]%MOD;
        }else{
            Mat a;
            a.init();
            a=a^(L-2);
            ans=a.getAns();
        }
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(dp,DFA,矩阵二分)