2 2 3
3 4
由于2是最小的素数,考虑长度为2的子串。红色为A,蓝色为B,则只有AA,AB,BA三种状况。对每种状况,在后面加上A或B,AA能够造成AA,AB,AB能够造成BA,BA能够造成AA。经过这个递推扩展到长度为n的状况,用矩阵快速幂加速便可。矩阵为:php
初始状况下,AA,AB,BA都有可能,所以最后将矩阵中的全部数字相加就是答案。ios
注意n为10的18次方会爆int因此在矩阵快速幂的时候要用long long【Matrix quickpow(Matrix A,ll k)】app
#include<iostream> #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #define INF 0x3f3f3f3f #define mod 1000000007 using namespace std; typedef long long ll; const int maxn = 100010; ll n; struct Matrix { ll a[5][5]; }; Matrix mul(Matrix x, Matrix y) { Matrix temp; for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) temp.a[i][j] = 0; for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { ll sum = 0; for (int k = 1; k <= 3; k++) { sum = (sum + x.a[i][k] * y.a[k][j] % mod) % mod; } temp.a[i][j] = sum; } } return temp; } Matrix quickpow(Matrix A,ll k) { Matrix res; res.a[1][1] = 1; res.a[1][2] = 0; res.a[1][3] = 0; res.a[2][1] = 0; res.a[2][2] = 1; res.a[2][3] = 0; res.a[3][1] = 0; res.a[3][2] = 0; res.a[3][3] = 1; while (k) { if (k & 1) res = mul(res, A); A = mul(A, A); k >>= 1; } return res; } int main() { int t; scanf("%d", &t); while (t--) { scanf("%lld", &n); if (n == 2) { printf("3\n"); continue; } Matrix A; A.a[1][1] = 1; A.a[1][2] = 0; A.a[1][3] = 1; A.a[2][1] = 1; A.a[2][2] = 0; A.a[2][3] = 0; A.a[3][1] = 0; A.a[3][2] = 1; A.a[3][3] = 0; Matrix res = quickpow(A, n - 2); ll x = (res.a[1][1] + res.a[1][2] + res.a[1][3]) % mod; ll y = (res.a[2][1] + res.a[2][2] + res.a[2][3]) % mod; ll z = (res.a[3][1] + res.a[3][2] + res.a[3][3]) % mod; printf("%lld\n", (x + y + z) % mod); } }
1018
101Matrix quickpow(Matrix A,ll k)】1018101810181018101810181018101810less