BJFU 1025 Ackermann函數解題報告(關於如何找規律)

描述

計算Ackermann函數值?天方夜譚吧?

不錯,Ackermann函數是增長速度極快的遞歸函數,要計算其函數值當然是相當困難的。

Ackermann函數定義如下:

本題中我們只需要計算當m=3時Ackermann函數的值

輸入

輸入包含多組測試數據,每組測試數據佔一行,爲一個64位整數n

輸出

對每組輸入的n,請輸出Ackermann函數當m=3時的值,也就是A(3,n)。最後結果對9223372036854775807取餘。

樣例輸入

5
10
100

樣例輸出

253
8189

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;
}
總結:要善於用暴力求解找到生活中的規律。。。生活中不是缺少規律,而是缺少暴力。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章