hdu3802 矩阵快速幂&特征方程&降幂

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

给定a、b、p、n,求以下式子的值

G(a,b,n,p)=(ap12+1)(bp12+1)[(a+b)2F(n)+(ab)2F(n)]

其中
F(n)={1F(n1)+F(n2)n=0,1n>1

其中 1a,b,n,p2109,pa,b<p

思路

这个式子的前两项 (ap12+1)(bp12+1) 用一个简单的快速幂就可以解决,关键在于后面的那一项
根据数列的特征方程的知识,可以将其转化为递推式,从而用矩阵快速幂来解决(关于数列的特征方程,不会的可以看一下这里
这里稍微说一下,这里怎么得到的递推式
我们先不考虑 F(n) ,因为这是一个斐波那契数列,一会再说

g(n)=(a+b)2n+(ab)2n

稍微化简一下可以得到
g(n)=(a+b+2ab)n+(a+bab)n

根据 x1=(a+b+2ab)   x2=(a+b2ab)
x1+x2=2(a+b)     x1x2=(ab)2
构造 特征方程
x22(a+b)x+(ab)2=0

可以得到递推式
g(n)=2(a+b)gn1(ab)2gn2

构造矩阵
[g(n)g(n1)]=[g(n1)g(n2)][2(a+b)(ab)210]

这里要注意一下,矩阵里面有一个负数,我们在初始化矩阵的时候就根据mod的值将其变成正数
g(n) 这一个我们解决了,然后就是求 g(n)F(n)g(F(n)) ,其中 F(n) 是斐波那契数列,数值会非常大,也要用矩阵快速幂来解决,在计算的过程中要取模,但由于F(n)是在指数上的,就不能随便取模,也就涉及到了降幂公式
AB AB mod φ(C) + φ(C) (mod C)   if Bφ(C)

其中 φ(C) 为欧拉函数,这里由于取模的数p是质数,不必考虑 Bφ(C) 这个条件,而且素数p的欧拉函数值即为p-1
也就是说,我们在计算 F(n) 的值的时候应该对 p1 取模,而不是p
到这里这个题就基本上解决了,然后就是实现的问题了,可以参考一下我的代码


具体代码如下:
Result:Accepted     Memory: 1740K     Time : 0MS

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
ll A,B,n,p;
int T;
ll ans;
ll a[2][2],b[2][2];
ll mod_pow(ll x,ll n, ll mod)
{
    x%=mod;
    ll res = 1;
    while(n>0)
    {
        if(n&1) res = res*x%mod;
        x = x*x%mod;
        n>>=1;
    }
    return res;
}
void mmul(ll a[2][2],ll b[2][2],ll s[2][2],ll mod)
{
    ll tmp[2][2];
    for(int i=0;i<2;i++)
       for(int j=0;j<2;j++)
       {
          tmp[i][j]=0;
          for(int k=0;k<2;k++)
             tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]%mod+mod)%mod;
         }
    for(int i=0;i<2;i++)
       for(int j=0;j<2;j++)
          s[i][j]=tmp[i][j];
}
ll f(ll n,ll mod)
{
    memset(a,0,sizeof(a));
    for(int i=0;i<2;i++)a[i][i]=1;
    memset(b,0,sizeof(b));
    b[0][0]=1;
    b[0][1]=1;
    b[1][0]=1;
    b[1][1]=0;
    n--;
    while(n)
    {
        if(n&1)mmul(a,b,a,mod);
        mmul(b,b,b,mod);
        n>>=1;
    }
    return (a[0][0]+a[0][1])%mod;
}
ll g(ll n,ll mod)
{
    memset(a,0,sizeof a);
    for(int i=0;i<2;i++) a[i][i]=1;
    memset(b,0,sizeof b);
    b[0][0] = 2*(A+B);
    b[0][1] = 1;
    b[1][0] = ((-(A-B)*(A-B))%mod+mod)%mod;//将矩阵中的负数处理成正数
    b[1][1] = 0;
    n--;
    n += p-1;
    while(n)
    {
        if(n&1) mmul(a,b,a,mod);
        mmul(b,b,b,mod);
        n>>=1;
    }
    return (a[0][0]*2*(A+B)%mod+2*a[1][0]%mod)%mod;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--)
    {
        cin>>A>>B>>n>>p;
        ans = (mod_pow(A,(p-1)/2,p)+1)%p;
        ans = ans*(mod_pow(B,(p-1)/2,p)+1)%p;
        ans = ans*(g(f(n,p-1),p)%p)%p;
        cout<<ans<<endl;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值