HDU 6030 Happy Necklace (递推+矩阵快速幂)

思路:

首先我们发现,当满足素数区间2,素数区间3的条件之后,下一个素数区间5乃至于之后的所有都会满足。(因为满足素数区间2,素数区间3的条件更强)
然后我们假设现在有一个数目为n的方案数为f(n)
(假设红的为1 蓝的为0 从而将此题简化成满足1的个数大于等于0的个数的一个二进制字符串的方案数)
那么我们考虑一下,能否从f(n-1)转移到f(n)呢?
考虑这个n-1位,后边如果加一个1,那么一定符合条件。(所以方案数可以加一个f(n-1))
那。。。如果最后一位加的是0呢?
此时我们不难发现,倒数第二位一定是1,只有这样才能满足素数区间2的条件。
进而得出倒数第三位一定是1,否则不能满足素数区间3的条件。
所以我们得出结论:f(n) = f(n-1) + f(n-3)
但是还没完,n的范围太大,我们无法将递推得到的结果保存起来。然而每次都递推又太慢,所以:矩阵快速幂。
构造一个3*3的矩阵:

Fn00Fn100Fn200(1)

然后构造一个右乘的矩阵
101100010(2)

矩阵1每次乘以矩阵2之后,n就会增长1,但是矩阵的格式不变,所以我们可以通过多次乘2矩阵来实现递推。而加速就在2矩阵的快速幂。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <queue>
#include <algorithm>
typedef long long int lli;
using namespace std;

#define N 3
const lli mod = 1e9+7;//注意这里要是没有const会慢3~4倍。
struct mat{
    lli mat[N][N];
};
mat operator *(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){
            for(int j=0;j<N;++j){
                c.mat[i][j] += a.mat[i][k]*(b.mat[k][j] % mod) % mod;
            }
        }
    }
    return c;
}

mat qp(mat a,lli k){
    mat c;
    for(int i=0;i<N;i++)
        for(int j =0;j<N;j++)
            c.mat[i][j] = (i==j);
    for(;k;k>>=1){
        if(k&1) c=c*a;
        a = a*a;
    }
    return c;
}

int main(){
    int t;
    cin>>t;
    lli n;
    while(t--){
        scanf("%lld",&n);
        if(n == 1){
            printf("1\n");
            continue;
        }
        mat a = {1,1,0,0,0,1,1,0,0};
        mat b = {6,4,3,0,0,0,0,0,0};
        a = qp(a,n-2);
        b = b * a;
        printf("%lld\n",b.mat[0][2] % mod);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值