Queuing
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4353 Accepted Submission(s): 1929

Now we define that ‘f’ is short for female and ‘m’ is short for male. If the queue’s length is L, then there are 2 L numbers of queues. For example, if L = 2, then they are ff, mm, fm, mf . If there exists a subqueue as fmf or fff, we call it O-queue else it is a E-queue.
Your task is to calculate the number of E-queues mod M with length L by writing a program.
3 8 4 7 4 8
6 2 1
题目大意:求长度为L的由m,f构成的字符串中,不包含fmf,fff的合法字符串的个数,在mod m 的意义下。
题解:矩阵优化DP递推式 : f[i]=f[i-1]+f[i-3]+f[i-4]
那么这个递推方程式是如何得来的呢?
f[i-1] 表示长度为i-1的序列的合法方案数,如果i-1是合法的那么当前位i 上一定可以填m,那么这样就计算出了所有在当前位填m的合法方案数。
因为填m的都已经计算过了,所以我们在来考虑填f的情况。
f[i-3] 表示长度为i-3的序列的合法方案数,i-3与i 之间相隔了两位,这两位共有4种选择mf,mm,ff,fm,只有mm 这一种选择无论第i-3位为m,还是f ,第i 位填f 一定成立。
f[i-4] 表示长度为i-4的序列的合法方案数,i-4与i 之间相隔了三位,这三位共有8中选择,出去不合法的选择,还剩三种mmm,fmm,mmf 我们可以发现如果选择mmm,fmm,的话与第i位的f,构成的合法序列的结尾都是mmf与f[i-3]的情况相同,所以只能选择mmf这一种填法。
初始矩阵:{f(i-3),f(i-2),f(i-1),f(i)}
优化矩阵:0 0 0 1
1 0 0 1
0 1 0 0
0 0 1 1
貌似递推式还有另一种证明法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 4
using namespace std;
int n,p,f[10];
struct data{
int a[10][10];
}a;
void clear(data &x)
{
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
x.a[i][j]=0;
}
void change(data &a,data b)
{
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
a.a[i][j]=b.a[i][j];
}
data mul(data a,data b)
{
data c;
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
{
c.a[i][j]=0;
for(int k=1;k<=N;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%p)%p;
}
return c;
}
data pow(data num,int x)
{
data ans; clear(ans);
for (int i=1;i<=N;i++) ans.a[i][i]=1;
data base; change(base,num);
while (x)
{
if (x&1) ans=mul(ans,base);
x>>=1;
base=mul(base,base);
}
return ans;
}
int main()
{
for (int i=2;i<=N;i++)
a.a[i][i-1]=1;
a.a[1][4]=1; a.a[2][4]=1; a.a[3][4]=0; a.a[4][4]=1;
f[1]=1; f[2]=2; f[3]=4; f[4]=6;
while (scanf("%d%d",&n,&p)!=EOF)
{
if (n<=3){
printf("%d\n",f[n+1]);
continue;
}
data ans=pow(a,n-3);
int t[10];
for (int j=1;j<=N;j++)
{
t[j]=0;
for (int k=1;k<=N;k++)
t[j]=(t[j]+f[k]*ans.a[k][j]%p)%p;
}
printf("%d\n",t[N]);
}
}