1. 程式人生 > >平方和階乘(一個繁瑣的高精 C++)

平方和階乘(一個繁瑣的高精 C++)

平方和階乘
題目限制
時間限制 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; } /*大家會發現這些程式碼很繁瑣,就是出現了一些很相似的地方,大家就像寫幾個子函式 但是我覺得呼叫函式需要時間,所以我覺得這樣寫執行時間短,但是寫函式在本題也不 會超時,所以有興趣的可以自己試一下,我就不上程式碼了 ^_^*/