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
__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;
}

结果: BJFU 1025 Ackermann函数解题报告(关于如何找规律)_第1张图片然后规律就出来了: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
#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;
}
总结:要善于用暴力求解找到生活中的规律。。。生活中不是缺少规律,而是缺少暴力。。。


你可能感兴趣的:(解题报告)