菜鳥の高速べき乗理解
15495 ワード
以前は高速べき乗について、どのように使うかしか知らなかったが、どの原理も分からなかった.コンピュータの構成原理とコンピュータネットワークを学んだ後、バイナリに敏感になった.8255のように、直接求めると255回の乗算を実行しなければならない.指数が大きいと、遅くなる.
255をバイナリで表すと8つの11111 1111ですが、実際には255=28*1+27*1+26*1+25*1+24*1+23*1+22*1+21*1+20*1=128+64+32+16+8+4+2+1+1+0指数をバイナリで表します.8(11111111)=8128*1*864*1*832*1*816*1*88*1*84*1*82*1*81*1*80*1で、右から左へカウントします.指数はそれぞれ128、64、32、16、8、4、2、1である.現在の指数は前の指数の2倍であるため、現在乗じなければならない数=前の乗数*前の乗数であり、現在の乗数がansに乗じられているかどうかは、現在位置するバイナリ数が1であるかどうかによって大きく減少する.もし数が大きいならば、テーマは型を取ることを要求して、毎回型を取ります.
高速べき乗を理解するには,線形代数における行列の乗算を理解するだけで,行列高速べき乗は必ず理解できる.
255をバイナリで表すと8つの11111 1111ですが、実際には255=28*1+27*1+26*1+25*1+24*1+23*1+22*1+21*1+20*1=128+64+32+16+8+4+2+1+1+0指数をバイナリで表します.8(11111111)=8128*1*864*1*832*1*816*1*88*1*84*1*82*1*81*1*80*1で、右から左へカウントします.指数はそれぞれ128、64、32、16、8、4、2、1である.現在の指数は前の指数の2倍であるため、現在乗じなければならない数=前の乗数*前の乗数であり、現在の乗数がansに乗じられているかどうかは、現在位置するバイナリ数が1であるかどうかによって大きく減少する.もし数が大きいならば、テーマは型を取ることを要求して、毎回型を取ります.
#include
using namespace std;
int qpow(int a, int b, int mod){
int ans = 1, tmp = a;
while(b){
if(b & 1){
ans = ans * tmp % mod;
}
tmp = tmp * tmp;
b = b >> 1;
}
return ans % mod;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", qpow(a, b, 100));
return 0;
}
高速べき乗を理解するには,線形代数における行列の乗算を理解するだけで,行列高速べき乗は必ず理解できる.
#include
#include
using namespace std;
const int N = 1e2;
const int mod = 1e5;
struct abc{
int t[N][N];
}a, ans;
void init(){
for(int i = 1; i <= N; ++i){
ans.t[i][i] = 1;
}
}
struct abc x(struct abc a, struct abc b, int n){
struct abc c;
memset(c.t, 0, sizeof(c.t));
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
for(int k = 1; k <= n; ++k){
c.t[i][j] = (c.t[i][j] + (a.t[i][k] * b.t[k][j]) % mod) % mod;
}
}
}
return c;
}
int main()
{
int b, n;
scanf("%d %d", &b, &n);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
scanf("%d", &a.t[i][j]);
}
}
init();
while(b){
if(b & 1){
ans = x(ans, a, n);
}
a = x(a, a, n);
b = b >> 1;
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
printf("%d ", ans.t[i][j]);
}
printf("
");
}
return 0;
}