A - Apple Trees -矩阵快速幂

A - Apple Trees

 Gym - 101845A 

  • 转自:http://zyl1213.top/blog/archives/1059
  • 题意:在第0年有一个0岁的苹果树,苹果树10岁会生16个0岁的苹果树,20岁会生9个0岁的苹果树,30岁会生4个0岁的苹果树,40岁会生一个0岁的苹果树,45岁这个这个苹果树就结束了它悲惨的一生。
  • 思路:一看就是递推关系,n是1e15,所以要用矩阵快速幂。
  • 因为会涉及到45岁死亡问题,所以把45分成了九份:
  • 0-4
  • 5-9
  • 10-14
  • 15-19
  • 20-24
  • 25-29
  • 30-34
  • 35-39
  • 40-44
  • 让f[n][0]表示第i年0-4的有多少个
  • 同理:
  • 我们可以五年五年的推导:
  • 递推关系有了,接下来就是转化成矩阵了。
  • 所以,
  • 那个问号表示什么呢??
  • 表示的是第0,1,2,3,4年中的某一个矩阵。
  • 因为我们是五年五年推的,n=6是,那么?表示的就是第一年,如果n=12,?表示的就是第2年。
  • 不过很明显,第0年到第4年的矩阵是相同的,所以?就是:
  • 这样矩阵关系就推完了。
 f[n][0]              0 16 0 9 0 4 0 1 0           

  f[n][1]              1 0 0 0 0 0 0 0 0           

  f[n][2]              0 1 0 0 0 0 0 0 0           

(  f[n][3]  )    =   (  0 0 1 0 0 0 0 0 0  ) 的(n/5)次方  *   (  ?  )

   f[n][4]              0 0 0 1 0 0 0 0 0            

   f[n][5]              0 0 0 0 1 0 0 0 0            

   f[n][6]              0 0 0 0 0 1 0 0 0            

   f[n][7]              0 0 0 0 0 0 1 0 0            

   f[n][8]              0 0 0 0 0 0 0 1 0  
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define md  1000000007
#define maxn 10
ll ans,b,n;
void mulp(ll x[9][9],ll y[9][9])
{
    ll z[maxn][maxn];
    memset(z,0,sizeof(z));
    for(int k=0; k<9; k++)
        for(int i=0; i<9; i++)
            for(int j=0; j<9; j++)
                z[i][j]=(z[i][j]+x[i][k]*y[k][j]%md)%md;
    for(int i=0; i<9; i++)
        for(int j=0; j<9; j++)
            x[i][j]=z[i][j];
}
int main()
{
    cin>>n;
    if(!n)
    {
        cout<<1<<endl;
        return 0;
    }
    b=n/5;
    ll a[9][9]= {0,16,0,9,0,4,0,1,0,
                 1,0,0,0,0,0,0,0,0,
                 0,1,0,0,0,0,0,0,0,
                 0,0,1,0,0,0,0,0,0,
                 0,0,0,1,0,0,0,0,0,
                 0,0,0,0,1,0,0,0,0,
                 0,0,0,0,0,1,0,0,0,
                 0,0,0,0,0,0,1,0,0,
                 0,0,0,0,0,0,0,1,0
                };
    ll e[9][9]= {1,0,0,0,0,0,0,0,0,
                 0,1,0,0,0,0,0,0,0,
                 0,0,1,0,0,0,0,0,0,
                 0,0,0,1,0,0,0,0,0,
                 0,0,0,0,1,0,0,0,0,
                 0,0,0,0,0,1,0,0,0,
                 0,0,0,0,0,0,1,0,0,
                 0,0,0,0,0,0,0,1,0,
                 0,0,0,0,0,0,0,0,1
                };
    while(b)
    {
        if(b%2)
            mulp(e,a);
        mulp(a,a);
        b/=2;
    }
    for(int i=0; i<9; i++)
        ans=(ans+e[i][0])%md;
    cout<<ans<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值