题意:给出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;
}