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;
}

 

posted @ 2017-05-07 21:43  Pacify  阅读(442)  评论(0编辑  收藏  举报