HDU 4565 So Easy! 解题报告

题目

比赛

题意:给出a,b,n,m,求的Sn。

思路:留意数据范围(a-1)^2<b<a^2,可知0<a-√b<1,不难想到(a+√b)^n+(a-√b)^n的和为整数,而0<(a-√b)^n<1,所以Sn=[(a+√b)^n+(a-√b)^n]%m,

           已知Sn的通项公式了,如果我们能求出它的递推公式,就能用矩阵乘法解决了。

           易知特征根为r1=a+√b,r2=a-√b,所以特征方程为r^2-(r1+r2)r+r1*r2=0,即r^2-2a*r+(a^2-b)=0,

           所以Sn的递推公式为Sn=2a*Sn-1+(b-a^2)*Sn-2。

        然后就构造矩阵:

   

           初始值S1=(a+√b)%m,S2=2*(a^2+b),于是这道题就变成矩阵乘法了。

代码:

//time:140ms
//memeroy:360KB
//length:1520B
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXN 110
#define FI first
#define SE second
using namespace std;

long long toz(long long n,long long mod)
{
    if(n>0) return n%mod;
    else    return mod-(-n)%mod;
}
void mul(long long a[2][2],long long b[2][2],long long mod)
{
    long long tmp[2][2]={{0}};
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j)
            for(int k=0;k<2;++k)
                tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j)
            a[i][j]=tmp[i][j];
}
void pow_mod(long long a[2][2],long long p,long long mod)
{
    long long ans[2][2]={{0}};
    ans[0][0]=ans[1][1]=1;
    while(p)
    {
        if(p&1) mul(ans,a,mod);
        mul(a,a,mod);
        p>>=1;
    }
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j)
            a[i][j]=ans[i][j];
}
int main()
{
    //freopen("/home/moor/Code/input.txt","r",stdin);
    long long  a,b,n,m,c,a1,a2;

    while(cin>>a>>b>>n>>m)
    {
        long long num[2][2];
        c=toz(-a*a+b,m);
        num[0][0]=2*a%m,num[0][1]=1;
        num[1][0]=c,num[1][1]=0;
        a1=(long long )ceil(a+sqrt(b*1.0))%m;
        a2=(2*a*a+2*b)%m;
        if(n>=3)
        {
            pow_mod(num,n-2,m);
            long long tmp[2][2]={{0}};
            tmp[0][0]=a2,tmp[0][1]=a1;
            mul(tmp,num,m);
            cout<<tmp[0][0]<<'\n';
        }
        else    cout<<(n==1?a1:a2)<<'\n';
    }
    //return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值