hdu 6030 矩阵快速幂
大致题意:
一条长度为n的项链,由红色珠子和蓝色珠子(分别用1和0表示)组成,在连续的素数子段中,红色珠子的个数不能少于蓝色珠子。问组成这个项链有多少种方案,求方案数模1000000007
分析:
首先我们看看边界情况n=2
01
10
11
有如上3种情况
再观察一下n=3的情况
011
101
111
110
这四个方案中有3种方案(011,101,111)有关联,n=2的情况再加一个1,结尾为1,那么肯定也有为结尾为0的情况。我们继续推测
n=4
0111
1011
1111
1101
0110
1110
前面四个,即n=3时再加一个1,后面两个是在n=1时加上110使结尾为0,但是n=1时0不应该是不满足条件吗。我们仔细看看题目,连续的素数子段,1并不是素数。
综上所述,加1或者加110。a(n)=a(n-1)+a(n-3)
初始状态是a2,不是a1
有了递推式,但是n又很大,所以我们得构造矩阵利用快速幂来求解。我们可以构造如下矩阵
a(n) a(n-1) a(n-2) = a(n-1) a(n-2) a(n-3) * 1 1 0
0 0 1
1 0 0
Mat=1 1 0
0 0 1
1 0 0
a(n) a(n-1) a(n-2) = a(4) a(3) a(2) * Mat^(n-4)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=3; typedef long long ll; const ll Mod=1000000000+7; struct Mat { ll mat[N+1][N+1]; }; Mat Multiply(Mat a, Mat b) { Mat c; memset(c.mat, 0, sizeof(c.mat)); for(int k = 0; k < N; ++k) for(int i = 0; i < N; ++i) if(a.mat[i][k]) for(int j = 0; j < N; ++j) if(b.mat[k][j]) c.mat[i][j] = (c.mat[i][j] +a.mat[i][k] * b.mat[k][j])%Mod; return c; } Mat QuickPower(Mat a, ll k) { Mat c; memset(c.mat,0,sizeof(c.mat)); for(int i = 0; i < N; ++i) c.mat[i][i]=1; for(; k; k >>= 1) { if(k&1) c = Multiply(c,a); a = Multiply(a,a); } return c; } int main() { int T; scanf("%d",&T); ll a[]={0,2,3,4,6}; Mat A; A.mat[0][0]=1,A.mat[0][1]=1,A.mat[0][2]=0; A.mat[1][0]=0,A.mat[1][1]=0,A.mat[1][2]=1; A.mat[2][0]=1,A.mat[2][1]=0,A.mat[2][2]=0; while(T--) { ll n; scanf("%I64d",&n); if(n<=4) { printf("%I64d\n",a[n]); continue; } Mat ans=QuickPower(A,n-4); printf("%I64d\n",(a[4]*ans.mat[0][0]+a[3]*ans.mat[1][0]+a[2]*ans.mat[2][0])%Mod); } return 0; }