ZOJ 2595 Ackerman's Function

本文介绍了一种求解Ackerman函数A(n,m)模t的高效算法,并提供了详细的实现思路与源代码。通过利用欧拉定理简化计算过程,解决了大数运算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ZOJ2595 Ackerman’s Function

downloadsource code (ZOJ2595.cpp) [recursion, number theory, Euler's theorem]

求Ackerman函数A(n, m)模t的值。

n\m 1 2 3 4 5
1 2 4 6 8 10 … (2m) 2 \times m …
2 2 4 8 16 32 … (2m2 \uparrow m  …
3 2 4 16 2222 22222 … (m2) 2 \uparrow\uparrow m …
4 2 4 65536 \begin{matrix}\underbrace{2^{2^{\cdot^{\cdot^{\cdot^2}}}}} \\ 65536 \end{matrix} overflow .. 2 \uparrow\uparrow\uparrow m …
5 2 4 overflow .. 2 \uparrow\uparrow\uparrow\uparrow m ..

上表中用到了Knuth’s up-arrow notation。从上面的表中可以看出n=1, n=2, m=1, m=2的时候问题都很简单,而事实

上n和m只要稍稍大一点,这个数就大得不得了,而它关于t的余数就是定值。证明就是利用欧拉定理

欧拉定理的内容是:如果a和n互质,那么aφ(n)=1(mod n);对于任意a, n和较大的b,有ab=aφ(n)+b mod φ(n)(mod n)。

于是利用欧拉定理,问题就很简单了,我们把上面问题的极限记为x=gao(a, b)。那么假设y=gao(a, φ(b)),就有

x=aφ(b)+ymod b,而如果b=1,显然x=0。

对于n=3&&m<32和n==4&&m==3的时候,结果未必收敛到了上面的极限,所以也要特殊处理,方法

类似求那个极限的递归。

Ackerman's Function

Time Limit: 10 Seconds       Memory Limit: 32768 KB

Ackerman's function is well known to all specialists in the theory of computation. It is the function in two positive integer arguments defined as follows:

It is not primitive recursive, more of that, A(i, i) grows faster than any primitive recursive function. In this problem your task is to calculate

A(n,m) mod t

for given t and several n and m. Here "x mod y" means the remainder of integer division of x by y - such r that 0 <= r < y and there exists integer q, such that x = qy + r.


Input

The input contains multiple test cases. The first line of the input is a single integer T (1 <= T <= 20) which is the number of test cases. T test cases follow, each preceded by a single blank line.

The first line of each test case contains t (1 <= t <= 100) and then several lines follow. Each of them contains two integers - n and m (1 <= m, n <= 100).

The last line of the test case contains two zeroes, it should not be processed.


Output

For each pair of integers in each test case, output its number followed by A(n, m) mod t. Use format shown in the sample output.

Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.


Sample Input

2

3
3 3
2 7
1 18
0 0

2
1 1
1 2
1 3
0 0

Sample Output

Case 1: 1
Case 2: 2
Case 3: 0

Case 1: 0
Case 2: 0
Case 3: 0


Author:  Andrew Stankevich
Source:  Andrew Stankevich's Contest #6
Submit     Status
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
#include <cmath>
ll phi(ll n)
{
    int m = sqrt(n + 0.5);
    ll ans = n;
    for(int i=2;i<=m;i++)
        if(n%i==0)
    {
        ans = ans / i * (i - 1);
        while(n%i==0) n/=i;
    }
    if(n>1) ans=ans/n*(n-1);
    return ans;
}
ll pow(ll a, ll b, ll m)
{
    ll ret = 1;
    for(a%=m;b;b>>=1,a=a*a%m) if(b&1) ret=ret*a%m;
    return ret;
}
ll t,n,m;
ll gao(ll n, ll b)
{
    if(n==1) return 2;
    if(n==2) return 4;
    if(n==3) return 16;
    if(n==4) return 65536;
    ll d = phi(b);
    return pow(2, d + gao(n-1, d), b);
}
ll gao(ll b)
{
    if(b==1) return 0;
    ll d = phi(b);
    return pow(2, d+gao(d), b);
}
int main()
{
    int re; cin>>re;
    bool blank=false;
    while(re--)
    {
        if(blank) puts("");
        blank=true;
        cin>>t;
        int ca=1;
        ll x = gao(t);
        while(cin>>n>>m)
        {
            if(n==0&&m==0) break;
            ll ans = 0;

            if(n==1)
            {
                ans = 2 * m % t;
            } else if(n==2) {
                ans = pow(2, m, t);
            } else if(n==3) {
                ans = gao(m, t) % t;
            }
            else
            {
                if( m==1) ans=2;
                else if(m==2) ans=4;
                else if(n==4&&m==3) ans=65536;///gao(4,t);
                else ans = x;
            }
            ans %= t;
            printf("Case %d: %lld\n", ca++, ans);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值