快速幂的算法函数:
int pow1(int a, int b)
{
int ans = 1;
while(b)
{
if(b&1)//相当于b%2==1,位运算,判断二进制最后一位是否为奇数
ans *= a;
a *= a;
b >>= 1;//位运算,将二进制右移一位,相当于b /= 2;
}
return ans;
}
快速幂取模:
int pow1(int a, int b, int c)//a的b次方,取模c
{
int ans = 1;
a = a % c;//积的取余等于取余的积的取余
while(b)
{
if(b & 1)//相当于b%2==1,位运算,判断二进制最后一位是否为奇数
ans = (ans * a) % c;
a = (a * a) % c;
b >>= 1;//位运算,将二进制右移一位,相当于b /= 2;
}
return ans;
}
矩阵的快速幂:
#define MAXN 15
#define MOD 10000007
typedef long long int LL;
LL res[MAXN][MAXN];
int N;
void M(LL a[MAXN][MAXN], LL b[MAXN][MAXN])//两个矩阵的相乘
{
LL ans[MAXN][MAXN];
memset(ans, 0, sizeof(ans));
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
for(int k=0;k<N;k++)
{
ans[i][j] = (ans[i][j]+a[i][k]*b[k][j]%MOD)%MOD;
}
}
}
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
a[i][j] = ans[i][j];
}
}
}
void K(LL a[MAXN][MAXN], int n )//矩阵的快速幂
{
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
//相比数的快速幂,把1变成单位矩阵
res[i][j] = (i==j);//res是单位矩阵
}
}
while(n)
{
if(n&1)
M(res, a);
M(a, a);
n >>= 1;
}
}
矩阵的快速幂:
高效计算矩阵的高次方。
简单的入门题目
think:
计算矩阵的高次方,然后取对角线之和。
#include <stdio.h>
#include <string.h>
#include <algorithm>
int k, m;
struct S
{
int r,c;
int a[15][15];
};
S ori,res;
void init()
{
memset(res.a,0,sizeof(res.a));
for(int i=1;i<=10;i++)
res.a[i][i]=1;
for(int i=2;i<=10;i++)
for(int j=1;j<=10;j++)
{
if(i-1!=j)
ori.a[i][j]=0;
else
ori.a[i][j]=1;
}
}
S maxtri(S x,S y)
{
S z;
memset(z.a,0,sizeof(z.a));
for(int i=1;i<=10;i++)
{
for(int k=1;k<=10;k++)
{
if(x.a[i][k]==0)
continue;
for(int j=1;j<=10;j++)
z.a[i][j]=(z.a[i][j]+(x.a[i][k]*y.a[k][j])%m)%m;
}
}
return z;
}
void maxtri_mod(int n)
{
while(n)
{
if(n&1)
res=maxtri(res,ori);
ori=maxtri(ori,ori);
n>>=1;
}
}
int main()
{
while(scanf("%d%d",&k,&m)!=EOF)
{
for(int i=1;i<=10;i++)
scanf("%d",&ori.a[1][i]);
init();
if(k<=9)
{
printf("%d\n",k%m);
continue;
}
maxtri_mod(k-9);
int sum=0;
for(int i=1;i<=10;i++)
{
sum+=(res.a[1][i]*(10-i))%m;
sum%=m;
}
printf("%d\n",sum%m);
}
return 0;
}
A - Jzzhu and Sequences
这算是一道矩阵快速幂的问题,不过有简单方法。
#include<stdio.h>
int main()
{
int x, m, y;
int a[20];
scanf("%d %d", &x, &y);
a[1]=x;
a[2]=y;
scanf("%d", &m);
//观察发现,此题目有规律,每六组一循环
for(int i=3; i<=6; i++)
{
a[i] = a[i-1] - a[i-2];
}
a[0] = a[6];
printf("%d\n", (((a[m%6]%1000000007)+1000000007)%1000000007));//可能有负数
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 15
#define MOD 10000007
typedef long long int LL;
LL res[MAXN][MAXN];
int N;
void M(LL a[MAXN][MAXN], LL b[MAXN][MAXN])
{
LL ans[MAXN][MAXN];
memset(ans, 0, sizeof(ans));
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
for(int k=0;k<N;k++)
{
ans[i][j] = (ans[i][j]+a[i][k]*b[k][j]%MOD)%MOD;
}
}
}
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
a[i][j] = ans[i][j];
}
}
}
void K(LL a[MAXN][MAXN], int n)
{
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
res[i][j] = (i==j);
}
}
while(n)
{
if(n&1)
M(res, a);
M(a, a);
n >>= 1;
}
}
int main()
{
int a, b;
LL A[MAXN];
LL AA[MAXN][MAXN];
while(~scanf("%d %d", &a,&b))
{
N = a + 2;
A[0] = 23;
A[a+1] = 3;
memset(AA, 0, sizeof(AA));
for(int i=1;i<=a;i++)
scanf("%lld", &A[i]);
for(int i=0;i<N;i++)
{
if(i!=N-1)
AA[i][0] = 10;
for(int j=1;j<=i;j++)
{
if(i!=N-1)
AA[i][j] = 1;
}
AA[i][N-1] = 1;
}
K(AA, b);
LL ans = 0;
for(int i=0;i<N;i++)
{
ans = (ans + A[i]*res[N-2][i]%MOD)%MOD;
}
printf("%lld\n", ans);
}
return 0;
}