我采用矩阵幂运算的思想,计算了N的阶乘。N小于1000都可计算
问题描述
输入一个正整数n,输出n!的值。
其中n!=1*2*3*…*n。
输入格式
输入包含一个正整数n,n<=1000。
输出格式
输出n!的准确值。
样例输入
10
样例输出
3628800
想法:
- 直接用整数表示,肯定不够用。32位的int类型好像最多只能表示到12的阶乘
- 乘法即加法,直接套用字符串类型整数相加的函数。这种写法直接超时
- 优化:采用矩阵幂运算的思想,减少计算次数。AC
#include <bits/stdc++.h>
using namespace std;
//将字符串倒置,方便计算
void traverse(char *str) {
int len = strlen(str);
for (int i = 0; i < len / 2; ++i) {
swap(str[i],str[len-i-1]);
}
}
//单纯的两个大整数相加
void add(char* a, char* b,char* res){
int carry=0;
int len = min(strlen(a),strlen(b));
for (int i = 0; i < len; ++i) {
int s=a[i]-'0'+b[i]-'0'+carry;
carry=s/10;
res[i]=s%10+'0';
}
if(len==strlen(a)) {
int i =len;
while (i<strlen(b)) {
int s;
if(i!=strlen(b)) s=b[i]-'0'+carry;
else s=carry;
carry=s/10;
res[i]=s%10+'0';
i++;
}
if(carry==0) res[i]='\0';
else {
res[i]=carry+'0';
res[i+1]='\0';
}
} else {
int i = len;
while (i<strlen(a)) {
int s;
if(i!=strlen(a)) s=a[i]-'0'+carry;
else s=carry;
carry=s/10;
res[i]=s%10+'0';
i++;
}
if(carry==0) res[i]='\0';
else {
res[i]=carry+'0';
res[i+1]='\0';
}
}
}
int main() {
freopen("../data","r",stdin);
char str[1000005]="1";
char res[1000005]="1";
int N;
scanf("%d",&N);
//如果不考虑超时,可以直接使用下面注释掉的for循环代替下面的for循环
// for(int i=2; i <= N;i++) {
// strcpy(str,res);
// for (int j = 0; j < i-1; j++) {
// add(str,res,res);
// }
// }
for (int i = 2; i <= N; i++) {
strcpy(str,res);
int M = i-1;
//如下采用了矩阵快速幂的模板算法
while (M) {
if(M&1) {
add(res,str,res);
}
M = M>>1;
add(str,str,str);
}
}
traverse(res);
puts(res);
}