描述
計算Ackermann函數值?天方夜譚吧?
不錯,Ackermann函數是增長速度極快的遞歸函數,要計算其函數值當然是相當困難的。
Ackermann函數定義如下:
本題中我們只需要計算當m=3時Ackermann函數的值
輸入
輸入包含多組測試數據,每組測試數據佔一行,爲一個64位整數n
輸出
對每組輸入的n,請輸出Ackermann函數當m=3時的值,也就是A(3,n)。最後結果對9223372036854775807取餘。
樣例輸入
5
10
100
樣例輸出
2538189
1099511627773
分析:如果直接用遞歸,你會發現n=0~9這個代碼是能用的,但是一旦n>=10,就出問題了。所以英俊的會長打出了n從0~9的值,發現了規律。下面是遞歸代碼:
#include<stdio.h>
__int64 Am(int m,int n)
{
if(m==0)
return n+1;
else
{
if(m>0&&n==0)
return Am(m-1,1);
else if(m>0&&n>0)
return Am(m-1,Am(m,n-1));
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
printf("%I64d\n",Am(3,n));
return 0;
}
結果:然後規律就出來了:a[0]=5,a[n]=2*a[n-1]-3;再用迭代法求出數列的通項公式:a[n]=2^(n+3)-3;
但是,要是這道題這樣就Ac了那就好了,那易彰彪也不會錯了9次了。。。題目說n是一個64位的整數。。如果按照這個公式算,電腦肯定爆炸。。。所以還是要找規律。。。然後繼續打。。輸入n,看結果會不會有規律。但是輸入之後才發現,就算取餘,結果也只能輸到59,一到60就超範圍了。。。所以60以後的項要靠手算。。。不過還好電腦自帶計算器。。然後算啊算,取餘啊取餘。。發現A[60]=9223372036854775805 A[61]=9223372036854775806 A[62]=1 A[63]=A[0]=5(取餘之後)...,那麼規律就出來了。。。A[n]=A[n%63]。再加上幾個特判代碼就完成了。。。但是交上去之後。。還是會超時!!!!考慮到oj的判別方式。。所以經過千辛萬苦如下Ac代碼就出來了:
#include<stdio.h>
#define N 9223372036854775807
__int64 F[60];
__int64 powhaha(int n)
{
__int64 ans=1,a=2;
while(n!=0)
{
if(n&1)
{
ans*=a;
ans%=N;
}
a*=a;
a%=N;
n>>=1;
}
return ans-3;
}
int main()
{
__int64 n,i;
for(i=0;i<=59;i++) //最後避免超時所以先全部算出來,然後用一個數組保存下來了。
F[i]=powhaha(i+3);
while(scanf("%I64d",&n)!=EOF)
{
n%=63;
if(n<=59)
printf("%I64d\n",F[n]);
else if(n==60)
printf("9223372036854775805\n");
else if(n==61)
printf("9223372036854775806\n");
else if(n==62)
printf("1\n");
}
return 0;
}
總結:要善於用暴力求解找到生活中的規律。。。生活中不是缺少規律,而是缺少暴力。。。