矩阵快速幂,递推
难度是递推关系,加入红色 用1表示, 蓝色用0 表示,一串就是一个 01 字符串。任意素数长度范围内,1 的个数 >= 0 的个数。
假如有一条合法的 01 串,位数是n, 合法项链数是 f(n). 在这条 01 串后面加1, 必然满足要求。
构成的长度 n + 1 的新串,以 1 结尾的合法串项链数 f(n)。
如果在这条n长度的 01 串后面加0, 相当于 长度为 n - 2 的 01 串后面加上 3位, 其中 第 n + 1 位确定是0, 剩下的第 n - 1 和 n 位, 有4种可能:
00, 01, 10, 11, 补上第 n + 1 位的0就是 000, 010, 100, 110. 显然只有 110 符合要求。
构成的长度 n + 1 的新串,以 0 结尾的合法串个数是 f(n - 2)
综上 f(n + 1) = f(n) + f(n - 2);
递推公式 n >= 4, f(n) = f(n- 1) + f(n - 3)
本题要点:
1、起始矩阵 res.m 如下
res.m[0][0] = f(4), res.m[0][1] = f(3), res.m[0][2] = f(2)
res.m[1][0] = 0, res.m[1][1] = 0, res.m[1][2] = 0
res.m[2][0] = 0, res.m[2][1] = 0, res.m[2][2] = 0
2、乘上矩阵 a.m 的 n - 4 的幂次, 矩阵 a.m 如下
a.m[0][0] = 1, a.m[0][1] = 1, a.m[0][2] = 0
a.m[1][0] = 0, a.m[1][1] = 0, a.m[1][2] = 1
a.m[2][0] = 1, a.m[2][1] = 0, a.m[2][2] = 0
3、注意 Matrix 的矩阵m一定要用 long long, 否则会爆 int
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 3;
int ans[5];
int T;
long long n, mod = 1e9 + 7;;
struct Matrix
{
long long m[MaxN][MaxN];
Matrix()
{
memset(m, 0, sizeof m);
}
};
Matrix multi(Matrix a, Matrix b)
{
Matrix res;
for(int i = 0; i < MaxN; ++i)
for(int j = 0; j < MaxN; ++j)
{
for(int k = 0; k < MaxN; ++k)
{
res.m[i][j] = (res.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;
} //m一定要用 long long, 否则会爆 int
}
return res;
}
Matrix fastm(Matrix res, Matrix a, long long n)
{
while(n)
{
if(n & 1)
{
res = multi(res, a);
}
a = multi(a, a);
n >>= 1;
}
return res;
}
void solve()
{
if(n <= 4)
{
printf("%d\n", ans[n]);
return;
}
Matrix res, a;
res.m[0][0] = ans[4], res.m[0][1] = ans[3], res.m[0][2] = ans[2];
a.m[0][0] = a.m[0][1] = a.m[1][2] = a.m[2][0] = 1;
res = fastm(res, a, n - 4);
printf("%lld\n", res.m[0][0]);
}
int main()
{
ans[4] = 6, ans[2] = 3, ans[3] = 4;
scanf("%d", &T);
while(T--)
{
scanf("%lld", &n);
solve();
}
return 0;
}
/*
2
2
3
*/
/*
3
4
*/