#官方题解:
https://www.luogu.org/discuss/show/53017
#1.P哥破解密码
#题目大意:
有
M
M
M组数据,每组给出一个数
N
N
N,回答在长度为
N
N
N的字符串中,填充
A
,
B
A,B
A,B,使得不存在连续3个
A
A
A出现的字符串有多少个。
#分析:
设
f
[
i
,
0
]
f[i,0]
f[i,0]表示长度为
i
i
i的合法字符串结尾的
A
A
A仅有
1
1
1个的个数。
f
[
i
,
1
]
f[i,1]
f[i,1]表示长度为
i
i
i的合法字符串结尾为
B
B
B的个数。
f
[
i
,
2
]
f[i,2]
f[i,2]表示长度为
i
i
i的合法字符串结尾的
A
A
A有
2
2
2个的个数。
则有
f
[
1
,
0
]
=
1
,
f
[
1
,
1
]
=
1
,
f
[
1
,
2
]
=
0
f[1,0]=1,f[1,1]=1,f[1,2]=0
f[1,0]=1,f[1,1]=1,f[1,2]=0
可以推出转移方程:
f
[
i
,
0
]
=
f
[
i
−
1
,
1
]
f[i,0]=f[i-1,1]
f[i,0]=f[i−1,1]
f
[
i
,
1
]
=
f
[
i
−
1
,
0
]
+
f
[
i
−
1
,
1
]
+
f
[
i
−
1
,
2
]
f[i,1]=f[i-1,0]+f[i-1,1]+f[i-1,2]
f[i,1]=f[i−1,0]+f[i−1,1]+f[i−1,2]
f
[
i
,
2
]
=
f
[
i
−
1
,
0
]
f[i,2]=f[i-1,0]
f[i,2]=f[i−1,0]
那么我们对这个东西可以利用矩阵乘法快速幂优化一下
#代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define mt(x) memset(x, 0 ,sizeof(x))
#define modn 19260817
using namespace std;
typedef long long ll;
ll a[3][3], f[3], n;
void Pre()
{
a[0][0] = 0, a[0][1] = 1, a[0][2] = 0;
a[1][0] = 1, a[1][1] = 1, a[1][2] = 1;
a[2][0] = 1, a[2][1] = 0, a[2][2] = 0;
f[0] = 1, f[1] = 1, f[2] = 0;
}
void mul()
{
ll c[3];
mt(c);
for (int i = 0; i < 3; i++)
for (int k = 0; k < 3; k++)
c[i] = (c[i] + f[k]*a[i][k]) % modn;
memcpy(f, c, sizeof(c));
}
void mulself()
{
ll c[3][3];
mt(c);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
c[i][j] = (c[i][j] + a[i][k]*a[k][j]) % modn;
memcpy(a, c, sizeof(c));
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
Pre();
scanf("%lld", &n);
if (n == 1)
{
printf("2\n");
continue;
}
n--;
for (; n ; n >>= 1)
{
if (n & 1) mul();
mulself();
}
printf("%lld\n", (f[0] + f[1] + f[2]) % modn);
}
return 0;
}