描述
计算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;
}
总结:要善于用暴力求解找到生活中的规律。。。生活中不是缺少规律,而是缺少暴力。。。