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