矩阵快速幂,longlong初始值

一道堵了我很久的题,被别人一说,就开窍了再见

题目描述

    有一群一共 n 个妖精和兽排成一队,其中这一队列可以全是妖精或者全是兽,当然也可以是妖精和兽并存。

    排队时还规定:兽不能落单(落单了就要被妖精砍死了),再明确一些,就是要么这个队列里面没有兽,如果有兽的话,必须 至少 两个兽肩并肩排在一起。

    请问有多少种排法呢?由于数可能很大,请你对这个结果对 1e9 + 7 取模。

输入

多组输入,请处理到文件结束。

数据组数不超过 20000。

一行一个数,代表 (n <= 10^10)。

输出

输出方案数,对 1e9 + 7 取模。


输入样例

1
2
3

输出样例

1
2
4

提示

假设妖精为 G,兽为 B。

n = 1 的情况: G n = 2 的情况: BB GG n = 3 的情况: BBG GGG GBB BBB

注意 n = 1 中没有 B 这种情况,因为这样算落单。


--------------------------------我是分界线-------------------------------------------


从它给的范围((n <= 10^10)),很显然这是一个找规律或者是快速幂的题目。

题目说B(兽,借用题目的提示)不能落单,必须连续的2个或者两个以上才合法,举例的话GBBGBB是合法的。

那么开始找规律:

1. 假设Y(n)表示为,输入为n的输出。

2. 假设T(n)表示为:合法的排列,且最后一个为G。例如:GGGG。

3. 假设S(n)表示为:“缺B合法排列”的排列数。表示在序列的最后,额外添加一个B,能够使这个序列变成合法的,例如:GBBGGGB。

4. 已知:Y(n-1),T(n-1),S(n-1)。

5. 求Y(n):那么我在这Y(n-1)个合法的序列中最后面添加一个G,这个新序列也是合法的,共有Y(n-1)中;我在这Y(n-1)个合法的序列中最后面添加一个B,只有[Y(n-1)-T(n-1)]种新序列是合法的;然后我在“缺B合法排列”后面加一个B,就会有新的S(n-1)中合法排列。Y(n)=Y(n-1)+[Y(n-1)-T(n-1)]+S(n-1)。

6. 求T(n):显然,T(n)=Y(n-1)。在n-1长的合法序列末加G。

7. 求S(n):显然,S(n)=T(n-1)。在n-1长的合法序列且以G结尾后面加个B。

8. 得到Y(n)=2*Y(n-1)-Y(n-2)+Y(n-3)。

得到上面那个式子后我就束手无策了.......在同学的点拨下,想起了矩阵快速幂大笑

其他的没什么说的,一个点被坑了一下,就是要使用long long。初始化的时候不知道为什么,初始化写 0L 也自动转化为int型数据了,最后我尝试初始化为 1000000007000L 就没事了,这也算是一点收获。

最后AC代码:

#include <iostream>

using namespace std;

#define M (long long)(1e9+7)

typedef struct Mat{
    long long c[3][3];
}Mat;

Mat calone(Mat a, Mat b);
long long speedcal(Mat s, long long n);

int main()
{
    long long N;
    while(cin>>N){
        Mat sta;//矩阵初始化操作很low...
        sta.c[0][0]=4L;sta.c[0][1]=2L;sta.c[0][2]=1L;
        sta.c[1][0]=0L;sta.c[1][1]=0L;sta.c[1][2]=0L;
        sta.c[2][0]=0L;sta.c[2][1]=0L;sta.c[2][2]=0L;
        long long ans=speedcal(sta,N);
        cout<<ans<<endl;
    }
    return 0;
}

long long speedcal(Mat s, long long n)
{
    if(n==1)
        return s.c[0][2];
    else if(n==2)
        return s.c[0][1];
    else if(n==3)
        return s.c[0][0];
    else{
        Mat m,t=s;
        m.c[0][0]=2L;m.c[0][1]=1L;m.c[0][2]=0L;
        m.c[1][0]=-1L;m.c[1][1]=0L;m.c[1][2]=1L;
        m.c[2][0]=1L;m.c[2][1]=0L;m.c[2][2]=0L;
        n-=3;
        while(n>0){
            if(n%2==1)
                t=calone(t,m);
            m=calone(m,m);
            n/=2;
        }
        return t.c[0][0];
    }
    return -1L;
}

Mat calone(Mat a, Mat b)
{
    Mat c;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            long long t=1000000007000L;//就是这里
            for(int k=0;k<3;k++){
                t=(t+a.c[i][k]%M*b.c[k][j]%M)%M;
            }
            c.c[i][j]=t;
            if(c.c[0][0]<0)
                cout<<"error"<<endl;
        }
    }
    return c;
} 
希望每天进步一点点~~







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值