昨晚大四的一个学长给我们讲了,距阵的使用,很不错,这里总结一下。
一般距阵,用在n很大,导致超时的问题上。它需要快速幂取模的辅助。
例子
求斐波那契数列 a1=1; a2=1; an=an-1+an-2; 求 an (n>=1&&n<=108) 由于n很大结果对999999999取模;
对于这题n很大你直接推,每次取%999999999,明显会超时,
矩阵做法
这样就可以化为 矩阵(a1 a2)*矩阵(An-1)= 矩阵(an,an+1);
看代码
#include<stdio.h>
#include<string.h>
#define mod 999999999
__int64 a[5];
__int64 b[3][3];
__int64 quick_mod(__int64 n)
{
a[1]=1; a[2]=1;
b[1][1]=0; b[1][2]=1;
b[2][1]=1; b[2][2]=1;
while(n)
{
if(n&1)
{
__int64 s1,s2;
s1=(a[1]*b[1][1]%mod+a[2]*b[2][1]%mod)%mod;
s2=(a[1]*b[2][1]%mod+a[2]*b[2][2]%mod)%mod;
a[1]=s1;
a[2]=s2;
n--;
}
n=n/2;
__int64 k1,k2,k3,k4;
k1=(b[1][1]*b[1][1]%mod+b[1][2]*b[2][1]%mod)%mod;
k2=(b[1][1]*b[2][1]%mod+b[1][2]*b[2][2]%mod)%mod;
k3=(b[2][1]*b[1][1]%mod+b[2][2]*b[2][1]%mod)%mod;
k4=(b[2][1]*b[1][2]%mod+b[2][2]*b[2][2]%mod)%mod;
b[1][1]=k1; b[1][2]=k2; b[2][1]=k3; b[2][2]=k4;
}
return a[1];
}
int main(void)
{
__int64 n;
while(scanf("%I64d",&n)==1)
{
printf("%I64d\n",quick_mod(n-1));
}
return 0;
}
这样就运用快速幂取模大大减少了时间。
如果矩阵大一点的话这样写
#include<stdio.h>
#include<string.h>
#define mod 999999999
__int64 a[5];
__int64 b[3][3];
__int64 quick_mod(__int64 n)
{
__int64 i,j,k;
a[1]=1; a[2]=1;
b[1][1]=0; b[1][2]=1;
b[2][1]=1; b[2][2]=1;
while(n)
{
if(n&1)
{
__int64 s[3];
memset(s,0,sizeof(s));
for(i=1;i<=2;i++)
{
for(j=1;j<=2;j++)
{
s[i]=(s[i]+a[j]*b[j][i])%mod;
}
}
for(i=1;i<=2;i++)
a[i]=s[i];
n--;
}
n=n/2;
__int64 kk[5][5];
memset(kk,0,sizeof(kk));
for(i=1;i<=2;i++)
{
for(j=1;j<=2;j++)
{
for(k=1;k<=2;k++)
{
kk[i][j]=(kk[i][j]+b[i][k]*b[k][j])%mod;
}
}
}
for(i=1;i<=2;i++)
{
for(j=1;j<=2;j++)
{
b[i][j]=kk[i][j];
}
}
}
return a[1];
}
int main(void)
{
__int64 n;
while(scanf("%I64d",&n)==1)
{
printf("%I64d\n",quick_mod(n-1));
}
return 0;
}