51nod 1113 矩阵快速幂
模版题
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%lld ",a) 10 #define ln printf(" ") 11 const int N=1e2+50; 12 const int MOD=1e9+7; 13 using namespace std; 14 int n,m; 15 ll a[N][N],b[N][N],c[N][N],ret[N][N]; 16 int read() 17 { 18 int s=0,t=1; char c=getchar(); 19 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 20 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 21 return s*t; 22 } 23 ll readl() 24 { 25 ll s=0,t=1; char c=getchar(); 26 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 27 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 28 return s*t; 29 } 30 void mul(ll a[N][N],ll b[N][N],int n) 31 { 32 ll sum=0; 33 memset(c,0,sizeof(c)); 34 for (int i=1;i<=n;i++){ 35 for (int j=1;j<=n;j++){ 36 sum=0; 37 for (int k=1;k<=n;k++) 38 sum+=(ll)(a[i][k]*b[k][j])%MOD; 39 c[i][j]=sum%MOD; 40 } 41 } 42 for (int i=1;i<=n;i++) 43 for (int j=1;j<=n;j++) 44 a[i][j]=c[i][j]; 45 } 46 void Pow() 47 { 48 for (int i=1;i<=n;i++) 49 ret[i][i]=1; 50 while (m){ 51 if (m&1) mul(ret,a,n); 52 mul(a,a,n); 53 m>>=1; 54 } 55 } 56 int main() 57 { 58 n=read(); m=read(); 59 for (int i=1;i<=n;i++) 60 for (int j=1;j<=n;j++) 61 a[i][j]=readl(); 62 Pow(); 63 for (int i=1;i<=n;i++){ 64 for (int j=1;j<=n;j++) 65 out(ret[i][j]); 66 ln; 67 } 68 return 0; 69 }
#10220. 「一本通 6.5 例 2」Fibonacci 第 n 项
经典题
构造一个 矩阵然后直接矩乘快速幂就行。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%lld",a) 10 #define ln printf(" ") 11 const int N=3; 12 const int MOD=1e9+7; 13 using namespace std; 14 ll n; 15 ll mod; 16 ll a[N][N],b[N][N],c[N][N],ret[N][N]; 17 int read() 18 { 19 int s=0,t=1; char c=getchar(); 20 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 21 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 22 return s*t; 23 } 24 ll readl() 25 { 26 ll s=0,t=1; char c=getchar(); 27 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 28 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 29 return s*t; 30 } 31 void mul(ll a[N][N],ll b[N][N]) 32 { 33 memset(c,0,sizeof(c)); 34 for (int i=1;i<=2;i++) 35 for (int j=1;j<=2;j++){ 36 ll sum=0; 37 for (int k=1;k<=2;k++) 38 sum+=(ll)(a[i][k]*b[k][j])%mod; 39 c[i][j]=sum%mod; 40 } 41 for (int i=1;i<=2;i++) 42 for (int j=1;j<=2;j++) 43 a[i][j]=c[i][j]; 44 } 45 void Pow() 46 { 47 for (int i=1;i<=2;i++) 48 ret[i][i]=1; 49 while (n){ 50 if (n&1) mul(ret,a); 51 mul(a,a); 52 n>>=1; 53 } 54 } 55 int main() 56 { 57 n=readl(),mod=readl(); n-=2; 58 a[1][1]=1; a[1][2]=1; 59 a[2][1]=1; a[2][2]=0; 60 Pow(); 61 out((ret[1][1]%mod+ret[2][1]%mod)%mod); 62 return 0; 63 }
#10221. 「一本通 6.5 例 3」Fibonacci 前 n 项和
求斐波那契数列前n项和。
设第n项和为s[n],构造一个1*3的矩阵s[n] f[n] f[n-1]
根据
s[n]=s[n-1]+f[n];
f[n+1]=f[n]+f[n-1];
构造矩阵,同理矩乘快速幂。
一次过就很舒服....
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%lld ",a) 10 #define ln printf(" ") 11 const int N=4; 12 const int MOD=1e9+7; 13 using namespace std; 14 ll n; 15 ll mod,ans; 16 ll a[N][N],b[N][N],c[N][N],ret[N][N]; 17 int read() 18 { 19 int s=0,t=1; char c=getchar(); 20 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 21 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 22 return s*t; 23 } 24 ll readl() 25 { 26 ll s=0,t=1; char c=getchar(); 27 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 28 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 29 return s*t; 30 } 31 void mul(ll a[N][N],ll b[N][N]) 32 { 33 memset(c,0,sizeof(c)); 34 for (int i=1;i<=3;i++) 35 for (int j=1;j<=3;j++){ 36 ll sum=0; 37 for (int k=1;k<=3;k++) 38 sum+=(ll)(a[i][k]*b[k][j])%mod; 39 c[i][j]=sum%mod; 40 } 41 for (int i=1;i<=3;i++) 42 for (int j=1;j<=3;j++) 43 a[i][j]=c[i][j]; 44 } 45 void Pow() 46 { 47 for (int i=1;i<=3;i++) 48 ret[i][i]=1; 49 while (n){ 50 if (n&1) mul(ret,a); 51 mul(a,a); 52 n>>=1; 53 } 54 } 55 int main() 56 { 57 n=readl(),mod=readl(); n--; 58 a[1][1]=1; a[1][2]=a[1][3]=0; 59 a[2][1]=a[2][2]=a[2][3]=1; 60 a[3][1]=0; a[3][2]=1; a[3][3]=0; 61 Pow(); 62 ans=(ret[1][1]+ret[2][1]+ret[3][1])%mod; 63 out(ans%mod); 64 return 0; 65 }
#10222. 「一本通 6.5 例 4」佳佳的 Fibonacci
做法很妙,只不过太弱想不出来。。
设p(n)=n*s(n)-T(n);
因为p(n)=(n-1)*f[1]+(n-2)*f[2]+....
可以推出p(n+1)时每个f(i)前面的系数就要+1,所以p(n+1)=p(n)+s(n).
根据这个递推式就可以愉快地构造了。
要注意的是p(1)=0!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 #include <map> 8 #define ll long long 9 #define out(a) printf("%lld ",a) 10 #define ln printf(" ") 11 const int N=5; 12 const int MOD=1e9+7; 13 using namespace std; 14 ll n,m; 15 ll mod,ans; 16 ll a[N][N],b[N][N],c[N][N],ret[N][N]; 17 int read() 18 { 19 int s=0,t=1; char c=getchar(); 20 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 21 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 22 return s*t; 23 } 24 ll readl() 25 { 26 ll s=0,t=1; char c=getchar(); 27 while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();} 28 while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();} 29 return s*t; 30 } 31 void mul(ll a[N][N],ll b[N][N]) 32 { 33 memset(c,0,sizeof(c)); 34 for (int i=1;i<=4;i++) 35 for (int j=1;j<=4;j++){ 36 ll sum=0; 37 for (int k=1;k<=4;k++) 38 sum+=(ll)(a[i][k]*b[k][j])%mod; 39 c[i][j]=sum%mod; 40 } 41 for (int i=1;i<=4;i++) 42 for (int j=1;j<=4;j++) 43 a[i][j]=c[i][j]; 44 } 45 void Pow() 46 { 47 for (int i=2;i<=4;i++) 48 ret[i][i]=1; 49 while (n){ 50 if (n&1) mul(ret,a); 51 mul(a,a); 52 n>>=1; 53 } 54 } 55 int main() 56 { 57 n=readl(),mod=readl(); m=n; n--; 58 a[1][1]=1; a[1][2]=a[1][3]=a[1][4]=0; 59 a[2][1]=a[2][2]=1; a[2][3]=a[2][4]=0; 60 a[3][1]=0; a[3][2]=a[3][3]=a[3][4]=1; 61 a[4][1]=a[4][2]=0; a[4][3]=1; a[4][4]=0; 62 Pow(); 63 ans=(ret[1][2]+ret[2][2]+ret[3][2]+ret[4][2])*m 64 -(ret[1][1]+ret[2][1]+ret[3][1]+ret[4][1]); 65 out(ans%mod); 66 return 0; 67 }