zoukankan      html  css  js  c++  java
  • 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
    ",a[n]);
                continue;
            }
            Mat ans=QuickPower(A,n-4);
            printf("%I64d
    ",(a[4]*ans.mat[0][0]+a[3]*ans.mat[1][0]+a[2]*ans.mat[2][0])%Mod);
        }
        return 0;
    }
  • 相关阅读:
    IO流(读取键盘录入)
    IO 流 自定义字节流的缓冲区-read 和write 的特点
    IO流 字节流的缓冲区
    IO流 拷贝图片
    IO流-字节流File读写操作
    IO流 带行号的缓冲区
    IO流(装饰设计模式)
    IO流-ReadLine方法的原理 自定义BufferedReader
    IO流 Buffered 综合练习
    IO流 BufferedWriter
  • 原文地址:https://www.cnblogs.com/pach/p/6822461.html
Copyright © 2011-2022 走看看