平方和階乘(一個繁瑣的高精 C++)
阿新 • • 發佈:2019-02-14
平方和階乘
題目限制
時間限制 1000ms 記憶體限制 1000KiB
題目描述 Description
小明是一個數學渣渣,但是老師總是讓他做一些很奇怪的題目。
這次小明又遇到麻煩了,老師告訴他一個數a,讓他求出這個數平方的階乘a1和這個數階乘的平方a2,還要a1a2的和,和a1a2的非負數差;
在a很小的時候,小明勉強能死算出答案;但是a很大的時候,小明就崩潰了。
請你為小明編一個程式解決這個問題。
輸入描述 Input Description
輸入一個正整數a。(1<=a<=250)
輸出描述 Output Description
第一行輸出a平方的階乘a1。
第二行輸出a階乘的平方a2。
第三行輸出a1+a2的值。
第四行輸出a1-a2的絕對值。
樣例輸入 Sample Input
3
樣例輸出 Sample Output
362880
36
362916
362844
資料範圍及提示 Data Size & Hint
1<=a<=250;
資料大到不可想象,務必使用高精。(不用可能1個測試點也不過)
a1=(aa)!;a2=(a!)(a!);
思路點拔:由於本題資料很大,所以我們需要使用高精度進行求解,首先計算平方的階乘,由於a的平方沒有爆,所以我們就用一個int型別的變數儲存a的平方的值,然後,我們就使用高精乘以低精的做法,然後我們那另一個數組把這個階乘的結果複製一份,然後就使用純粹的高精乘,然後就用一個高精加和一個高精減就可以了,唯一要強調的就是:陣列開得有點多,所以不要搞混淆了。
上程式碼!!
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int a[1000005]={0,1},x,w=1,b[1000005]={0,1},c[1000005],d[2000005],e[1000005],f[1000005];
char a1[100005],d1[100005];
int main()
{
int n;
scanf("%d",&n);
int p=n*n; //儲存n的平方
for(int i=2;i<=p;i++) //計算平方的階乘
{
x=0; //在內層迴圈與外層迴圈之間將借位清0
for(int j=1;j<=w;j++){a[j]=a[j]*i+x;x=a[j]/10;a[j]%=10;} //計算
while(x){a[++w]=x%10;x/=10;} //處理進位
}
for(int i=w;i>=1;i--) printf("%d",a[i]); //輸出平方的階乘的結果
printf("\n");
int lena=w; //儲存結果的長度,便於一會使用
w=1; //將位數重新變為1
for(int i=2;i<=n;i++) //首先計算n的階乘,由於n<=250,所以也需要使用高精度
{
x=0; //借位清0
for(int j=1;j<=w;j++){b[j]=b[j]*i+x;x=b[j]/10;b[j]%=10;} //計算
while(x>0){b[++w]=x%10;x/=10;}//處理進位
}
for(int i=1;i<=w;i++) c[i]=b[i]; //複製一份,以便下面使用
for(int i=1;i<=w;i++)
{
x=0; //同樣將借位清空
for(int j=1;j<=w;j++)
{
d[i+j-1]=b[i]*c[j]+d[i+j-1]+x; //計算
x=d[i+j-1]/10;
d[i+j-1]%=10; //處理進位
}
d[i+w]=x; //處理最高位的進位
}
int lenc=2*w;
while(d[lenc]==0&&lenc>1) lenc--; //去除前導0
for(int i=lenc;i>=1;i--) printf("%d",d[i]); //輸出平方的階乘的結果
printf("\n");
int lenb=lenc,lend=1; //lenb用來儲存長度,lend用來儲存和的長度
x=0;
while(lend<=lena||lend<=lenb) //高精加
{
e[lend]=a[lend]+d[lend]+x; //計算
x=e[lend]/10;
e[lend]%=10; //處理進位
lend++;
}
e[lend]=x; //處理最高位
while(e[lend]==0&&lend>1) lend--; //去除前導0
for(int i=lend;i>=1;i--) printf("%d",e[i]);
//輸出平方的階乘與結成的額平方的和
printf("\n");
for(int i=1;i<=lena;i++) a1[i]=a[i]+'0';
//將它們先轉化為字串,一會好使用函式,更方便一些
for(int i=1;i<=lenb;i++) d1[i]=d[i]+'0';
if(lena<lenb||(lena==lenb&&strcmp(a1,d1)<0))
//比較兩個數的大小,如果前一個數小於後一個數
{
swap(lena,lenb); //就需要交換長度與串
swap(a1,d1);
}
for(int i=1;i<=lena;i++) a[i]=a1[i]-'0';
//然後將它們重新轉化為整形,方便下面計算
for(int j=1;j<=lenb;j++) d[j]=d1[j]-'0';
int i=1; //i用來儲存結果的位數
while(i<=lena)
{
if(a[i]<d[i]){a[i+1]--;a[i]+=10;} //處理借位
f[i]=a[i]-d[i];//計算
i++;
}
while(f[i]==0&&i>1) i--; //去除前導0
int lenans=i;
//由於i是定義在外面的,所以和for迴圈裡面的i不影響,但是輸出是就有問題了
for(int i=lenans;i>=1;i--) printf("%d",f[i]); //輸出
return 0;
}
/*大家會發現這些程式碼很繁瑣,就是出現了一些很相似的地方,大家就像寫幾個子函式
但是我覺得呼叫函式需要時間,所以我覺得這樣寫執行時間短,但是寫函式在本題也不
會超時,所以有興趣的可以自己試一下,我就不上程式碼了 ^_^*/