HDU2256
求
(2√+3√)2nmod1024
直接用double求,2n次乘法肯定会损失精度,可以构造递推关系去求解
(2√+3√)2nmod1024=(5+26√)nmod1024
而 (5+26√)nmod1024 我们是可以通过构造递推关系求解的
构造方程 x2−10x+2=0 的根是 5+26√
这样根据方程与递推公式的关系:
f(n)=10f(n−1)−f(n−2)⇒f(1)=10,f(2)=98
推出该递推关系式为:
f(n)=(5+26√)n+(5−26√)n
又因为 (5−26√)n<1 ,最后得到
(5+26√)n=f(n)−1
f(n)我们可以通过递推关系求得:
(f(n)f(n−1))=(101−10)∗(f(n−1)f(n−2))=tn−2∗(f(2)f(1))
其中t为状态转移矩阵,最后通过矩阵快速幂可以求出来结果
最后注意一下负数取模的处理,加模取模
AC代码:
/************************************************
* By: Xingxing *
* Date: 2016-09-26 *
* Address: http://blog.csdn.net/legend_pawn?viewmode=contents*
***********************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
ll n;
const int mod=1024;
const int N=2; //矩阵维数
struct mat{
ll m[N][N];
mat() {}
mat unit(){ //单位矩阵
for(int i=0;i<N;i++)
for(int j=0;j<=N;j++)
m[i][j]=i==j?1:0;
}
};
mat t; //t为状态转移矩阵
mat operator * (mat a,mat b){ //方阵乘法
mat res;
for(int i=0;i<N;i++)
for(int j=0;j<=N;j++){
res.m[i][j]=0;
for(int k=0;k<N;k++)
res.m[i][j]+=(((a.m[i][k]%mod)*(b.m[k][j]%mod))+mod)%mod;
}
return res;
}
mat operator ^ (mat res,ll n){ //方阵二分幂
res.unit();
while(n>=1){
if(n&1)
res=res*t;
n=n>>1;
t=t*t;
}
return res;
}
void init(){ //状态转移矩阵的初始化
t.m[0][0]=10;t.m[0][1]=-1;
t.m[1][0]=1;t.m[1][1]=0;
}
int main(){
freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
scanf("%lld",&n);
if(n==1){
printf("9\n");
continue;
}
else if(n==2){
printf("97\n");
continue;
}
else{
ll ans;
init();
mat a;
memset(a.m,0,sizeof(a.m));
a=t^(n-2);
ans=(98*a.m[0][0])%mod+(a.m[0][1]*10)%mod;
ans=(ans+mod)%mod;
printf("%lld\n",ans-1);
}
}
return 0;
}