[矩阵快速幂/推函数式]Codeforces185A Plant

Codeforces185A Plant

题意:
就如图所示,求尖朝上的三角形有几个
思路1(推函数式):
这道题比起矩阵乘法更容易推出公式

123
总三角数2^2 = 42^4 = 162^16
尖三角数31036

先将三角形从右下角开始,计有n层,我们可以得知(1~n)层有(1、2……n)个尖朝上的三角形,所以我们推出公式:(1+n)*n/2;
然后我们求n,我们可以发现1年后有2层,2年后有4层,3年后有8层……可以推出n年后有2^n层
所以最终公式为:(1 + 2^n)*2^(n-1);

代码1(推函数式):

/**************************************************************
    Problem: CF_185A
    User: soundwave
    Language: C++
    Result: Accepted
    Time: 30ms
    Memory: 2000KB
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <stdio.h>

using namespace std;
typedef __int64 LL;
const LL MOD = 1e9+7;
//二分快速幂
LL my_pow(LL x, LL c){
    LL re = 1;
    while(c>0){
        if(c&1) re = (re*x) % MOD;
        x = (x*x) % MOD;
        c>>=1;
    }
    return re;
}
int main(){
    LL n;
    scanf("%I64d", &n);
    if(n==0){
        printf("1\n");
        return 0;
    }
    LL re = my_pow(2,n-1);
    printf("%I64d\n", (re*((re*2+1)%MOD)) % MOD);
    return 0;
}
思路2(矩阵快速幂):

矩阵乘法最重要的是要推出通项公式,这道题一看就是符合等差/等比数列的有规律的题
f(1)=3, f(2)=10, f(3)=36, f(4)=136;
根据前几项,可以推出通项公式:f(n) = 4*f(n-1) - 2^(n-1);
然后将之转化为矩阵乘法

4-1
02
*

f(n-1)
2^(n-1)
=

f(n)
2^n
可以总结出

f(n)
2^n
=

4-1
02
的(n-1)次幂

*

3
1
还需要注意的一点是,当 n=1 时特判

代码2(矩阵快速幂):

/**************************************************************
    Problem: CF_185A
    User: soundwave
    Language: C++
    Result: Accepted
    Time: 30ms
    Memory: 2000KB
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <stdio.h>
#include <vector>
/*
通项公式:f(n) = 1                   (n==0);
                 4*f(n-1) - 2^(n-1)  (n!=0);

4 -1		f(n-1)		f(n)
0 2	    *	2^(n-1)	=	2^n
*/
using namespace std;
typedef vector<int>Vint;
typedef vector<Vint>VVint;
typedef __int64 LL;
const int MOD = 1024;
//矩阵乘法
VVint calc(VVint &A, VVint &B){
    VVint C(A.size(), Vint(A.size()));
    for(int i=0; i<A.size(); i++)
    for(int j=0; j<B[0].size(); j++)
    for(int k=0; k<B.size(); k++)
        C[i][j] = (C[i][j] + (A[i][k]*B[k][j])%MOD) % MOD;
    return C;
}
//二分快速幂
VVint my_pow(VVint &A, LL c){
    VVint B(A.size(), Vint(A.size()));
    if(c==0){
        B[0][0] = 0;
        B[0][1] = 1;
        return B;
    }
    for(int i=0; i<A.size(); i++)
        B[i][i] = 1;
    while(c>0){
        if(c&1) B = calc(B,A);
        A = calc(A,A);
        c>>=1;
    }
    return B;
}
int main(){
    int t;
    LL n;
    scanf("%I64d", &n);
    VVint A(2, Vint(2));
    A[0][0]=4, A[0][1]=-1;
    A[1][0]=0, A[1][1]=2;
    A = my_pow(A, n-1);
    LL re = 0;
    re = ((A[0][0]*3)%MOD + A[0][1]) % MOD;
    printf("%I64d\n", re);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值