HDU 4565 So Easy! 递推数列+矩阵快速幂

7 篇文章 0 订阅

题目链接点这儿

就是求这个式子的值。。。第一眼。。。太鬼畜了。。。完全是不可做啊。。。

结果。。。练习赛过了会儿之后,,,有人做出来了。。。只好去瞪了。。。发现题目里有个条件(a-1)2< b < a也就是说a-1<sqrt(b)<a 这个有什么用呢。。我们可以凑一个跟所求式对称的式子 (a-sqrt(b))^n.。。。这个式子是小于1的,而且这个式子和所求式相加是一个整数(这个凑对称在和二项式相关的问题里还是经常用到的。。)那么Sn就是两个式子的值了。。。

那么,Sn = a^n+b^n。。。这很明显Sn有一个二阶常系数线性齐次的递推公式(一个差分方程),我们将它求出来之后,就可以用矩阵快速幂求第n项了。。

特征根为a+sqrt(b)和a-sqrt(b)。。。两个系数一个是2*a 一个是b-a^2(韦达定理求系数)然后只剩敲一个矩阵乘法了。。

下面放出代码

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <climits>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(i,initial_n,end_n) for(ll (i)=(initial_n);(i)<(end_n);i++)
#define repp(i,initial_n,end_n) for(ll (i)=(initial_n);(i)<=(end_n);(i)++)
#define reep(i,initial_n,end_n) for((i)=(initial_n);(i)<(end_n);i++)
#define reepp(i,initial_n,end_n) for((i)=(initial_n);(i)<=(end_n);(i)++)
#define eps 1.0e-9
#define MAX_N 1010

using namespace std;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef __int64 ll;
typedef unsigned __int64 ull;


int main(){
    ll a, b, n, m;
    while(scanf("%I64d%I64d%I64d%I64d",&a,&b,&n,&m)!=EOF){
        ll xishu[2][2]={2*a,b-a*a,1,0};
        ll ans[2]={2*a,2};
        while(n) {
            if(n&1) {
                ll a0,a1;
                a0=(xishu[0][0]*ans[0]+xishu[0][1]*ans[1])%m;
                a1=(xishu[1][0]*ans[0]+xishu[1][1]*ans[1])%m;
                ans[0]=a0;
                ans[1]=a1;
            }
            n/=2;
            ll a0,a1,a2,a3;
            a0=(xishu[0][0]*xishu[0][0]+xishu[0][1]*xishu[1][0])%m;
            a1=(xishu[0][0]*xishu[0][1]+xishu[0][1]*xishu[1][1])%m;
            a2=(xishu[1][0]*xishu[0][0]+xishu[1][1]*xishu[1][0])%m;
            a3=(xishu[1][0]*xishu[0][1]+xishu[1][1]*xishu[1][1])%m;
            xishu[0][0]=a0;
            xishu[0][1]=a1;
            xishu[1][0]=a2;
            xishu[1][1]=a3;
        }
        printf("%I64d\n",(ans[1]+m)%m);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值