题目链接: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;
}
本文介绍了一道经典的字符串计数问题,利用有限自动机(DFA)原理,通过构建状态转移矩阵并进行快速幂运算来高效解决长度限制下特定子串禁止的问题。
3万+

被折叠的 条评论
为什么被折叠?



