距阵的运用

昨晚大四的一个学长给我们讲了,距阵的使用,很不错,这里总结一下。

一般距阵,用在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 ",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 ",quick_mod(n-1));
}
return 0;
}

原文地址:https://www.cnblogs.com/liudehao/p/4148258.html