Description
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.
Input
Output
Sample Input
3 8
4 7
4 8
Sample Output
6
2
1
分析
dp
状态转移方程的推导
计算f(n)时,当第 n 位为 m 时,对前面无影响,所以记f1 = f(n-1),当第 n 位为 f 时,观察后两位,不论后两位为 mf 还是 ff 都会对前面产生限制,继续观察后三位,若后三位为 fff 和 fmf 时不满足条件,当结尾为 mmf 时对前面无影响,记 f2 = f(n-3),当结尾为 mff 时,对前面产生限制,继续观察后四位,mmff和fmff中,只有mmff符合条件且不会对前面产生影响,记 f3 = f(n-4)。至此,所有可能的条件都已经找齐,所以 f(n) = f1 + f2 + f3,即 f(n) = f(n-1) + f(n-3) + f(n-4)。
矩阵快速幂
构造的矩阵A为 4*4 的矩阵,如下
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 1
要求 f(n),只需乘 n-3 次即可。
AC代码如下
#include<cstdio>
#include<cstring>
#define maxn 4
using namespace std;
struct S
{
int m[4][4];
};
int a[maxn];
int l,m;
S mul(S a,S b)
{
S c;
memset(c.m,0,sizeof(c.m));
for(int i = 0 ; i < 4 ; i++)
for(int j = 0 ; j < 4 ; j++)
{
for(int k = 0 ; k < 4 ; k++)
c.m[i][j] += a.m[i][k] * b.m[k][j];
c.m[i][j] %= m;
}
return c;
}
S quick_power(S a,int k)
{
if(k == 1) return a;
else if(k & 1) return mul(quick_power(a,k-1),a);
else
{
S c = quick_power(a,k >> 1);
return mul(c,c);
}
}
int main()
{
a[0] = 1,a[1] = 2,a[2] = 4,a[3] = 6;
S c;
for(int i = 0 ; i < 4 ; i++)
if(i == 2) c.m[3][i] = 0;
else c.m[3][i] = 1;
for(int i = 0 ; i < 3; i++)
for(int j = 0 ; j < 4; j++)
{
if(j == i + 1) c.m[i][j] = 1;
else c.m[i][j] = 0;
}
while(~scanf("%d%d",&l,&m))
{
if(l < 4)
{
printf("%d\n",a[l]%m);
continue;
}
S b = quick_power(c,l-3);
int ans = 0;
for(int i = 0 ; i < 4 ; i++)
ans += (b.m[3][i] * a[i]) % m;
printf("%d\n",ans%m);
}
return 0;
}
1033



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



