题目链接: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; }