hdu 6030 矩阵快速幂


题意: 给出红蓝两种,然后排成一个字符串,要求在每一个长度为素数的区间里面是的r(red)的数量不小与b(blue)的数量;


思路:想象当n为2的时候的情况是 rr,rb,br,三种情况,当n为3的时候相当于在后面添加一个b或者r,会发现形成rr的情况是前面rr和br的和,形成br的情况是前面的rb,而形成rb的情况是前面的rr,不能有前面的br形成rb,因为在素数为3的时候不能形成brb;

所以你会发现这个针对的素数只是2和3;

根据递推,设数组a[],b[],c[]分别为后面两个字母为rr,br,rb的字符串的数量,那么可以得到递推式:

a[i] = a[i - 1] + c[i - 1];b[i] = a[i - 1];c[i] = b[i - 1];

而题中要求的是所有的字符串,即s[n] = a[n] + b[n] + c[n];

可以得出s[i] = s[i - 1] + s[i - 3];

n的范围是10^18,那么只能用到矩阵快速幂:

可以推出最初的矩阵为 1 0 1

                                         1 0 0 

                                         0 1 0


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<string>
using namespace std;
#define clr(x,y) memset(x,y,sizeof x)
const int maxn = 1000000 + 10;
const double pp = 10e8;
typedef long long ll;
const ll SMod = 1000000007;


struct Matrix
{
    ll m[3][3];
};
Matrix Mul(Matrix a,Matrix b)
{
    Matrix c;
    memset(c.m,0,sizeof(c.m));
    for(ll i=0;i<3;i++)
        for(ll j=0;j<3;j++)
            for(ll k=0;k<3;k++)
                c.m[i][j] += ((a.m[i][k]*b.m[k][j])%SMod + SMod)%SMod;
    return c;
}

Matrix pow_mod(Matrix a,ll n)
{
    Matrix res;
    memset(res.m,0,sizeof(res.m));
    res.m[0][0] = res.m[1][1] = res.m[2][2]  =  1;
    while(n)
    {
        if(n&1)
            res = Mul(res,a);
        n>>=1;
        a = Mul(a,a);
    }
    return res;
}
Matrix p =
{
    1,0,1,
    1,0,0,
    0,1,0
};
ll a[10];
int main()
{
    ll Tcase;
    scanf("%I64d",&Tcase);
    a[2] = 3;
    a[3] = 4;
    a[4] = 6;
    a[5] = 9;
    while(Tcase --)
    {
        ll n;
        scanf("%I64d",&n);
        if(n <= 5)
        {
            printf("%I64d\n",a[n]);
            continue;
        }
        Matrix t = pow_mod(p,n - 5);
        ll ans = (t.m[0][0] * a[5] % SMod+ t.m[0][1] * a[4] %SMod + t.m[0][2] * a[3] %SMod ) % SMod;
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值