注:笔者是一名十八线蒟蒻 ,因此文中可能有许多 ,请大佬们在评论区下留言,我会尽快改进。
原题
时间限制:
,空间限制:
In Complexity theory, some functions are nearly
, but it is greater then
. For example, the complexity of a typical disjoint set is
. Here
is Inverse Ackermann Function, which growth speed is very slow. So in practical application, we often assume
.
However is greater than , that means if is large enough, can greater than any constant value.
Now your task is let another slowly function
reach a constant value
. Here
is iterated logarithm function, it means “the number of times the logarithm function iteratively applied on
before the result is less than logarithm base
”.
Formally, consider a iterated logarithm function
Find the minimum positive integer argument
, let
The answer may be very large, so just print the result
after mod
.
Input
The first line of the input is a single integer
indicating the number of test cases.
Each of the following lines contains integers , and .
Note that if
, we consider the minimum number
is
.
Output
For each test case, output
mod
in a single line.
Hint
In the
query,
and
. Then
, so the output is
mod
=
.
样例输入
5
2 0 3
3 1 2
3 1 100
3 2 16
5 3 233
样例输出
1
1
3
11
223
题面分析
总结起来就是:给出
与
的计算方法,求最小的正整数
,使得
, 输出
**
一般对于数学题,我们可以先试几个数来找找规律。
我们以
为例,建议以下过程读者可以自己手推或者利用代码暴力打表。
当
时,
。
当
时,倒推回去可以得到
。
同理,
时,得到
。
时,
。
时,
。
写到这里我们似乎看到了规律:
是
,
是
,
是
,
是
,所以我们总结以下得到
答案是
。
那为了确认这个结论是否正确,我们再以
为例,请读者试着自行推导。
当然我们同样可以得到答案是
。
所以,我们可以假设:对于
,答案为
。
数学题就是大胆猜想从不求证。但为了显得这篇博客很正经还是证明一下
证明:我们将
记为
,则
于是该问题就转化为求这个幂塔函数
的结果。
因为
,
,
,暴力算法直接超出范围,队友赛后用
纯暴力算到超时,因此考虑新的策略。
我们可以先处理简单的情况:
是个很大的数字,如果可以处理的话就可以递归解决问题。
这里就要请出本题的主角:欧拉降幂。
欧拉降幂
首先,我们有费马小定理
。
又因为
,因此我们有
。
所以
,我们称之为 欧拉降幂 。
但在本题中,
不一定为
,因此我们引入扩展欧拉降幂。
扩展欧拉降幂
首先我们给出结论
以下是证明,可以选择性跳过毕竟会用就行 。
当
时易知。
当
时证明如下:
( 以下证明内容来自 scau_bi 的CN博客 https://www.cnblogs.com/bibibi/p/10269051.html)
首先我们证明一个引理。
引理:对于
的一个质数因子
,有
证:
我们设
有
(费马小定理)
因为
(
是积性函数,即
)
故
我们设
两边同乘
,得
所以
于是我们可以把这个式子推广,得到
--------------------(①)
又因为
(因为对于
,除了
的倍数以外都与其互质,因此
)
(这一步的证明:
时可以用导数易得其成立。
时
。
这里利用了
,因为
是
)
因此
因为
,故
那我们利用①式得到
--------------------(②)
而对于
,我们也可以通过②式有
因此,我们把一个任意数
拆成
,则相乘后可以得到
终于证毕。建议想学懂原理的读者自行手推一遍!
好,有了解决的办法,我们就考虑递归写一个函数
,
为递归的层数,
是当前的模数。
每一次都利用快速幂实现
的调用。到最后一层返回
或者
。
注意在回溯时快速幂的结果也要根据扩展欧拉降幂进行改变!
AC代码(4ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
long long a,b,m;
long long phi(long long n)
{
long long ans = n;
for(int i = 2; i*i <= n; i++)
{
if(n % i == 0)
{
ans -= ans/i; //等价于通项,把n乘进去
while(n % i == 0) //确保下一个i是n的素因数
n /= i;
}
}
if(n > 1)ans -= ans/n; //最后可能还剩下一个素因数没有除
return ans;
}
long long MOD(long long a,long long mm)//扩展欧几里得的结果
{
return a>=mm?a%(mm)+(mm):a;
}
long long qsm(long long a,long long b,long long c)//快速幂
{
if(!c)
return 0;
long long ans=1,base=a;
while(b!=0)
{
if(b&1)
ans=MOD(ans*base,c);
base=MOD(base*base,c);//注意这两行!回溯时也要根据扩展欧拉降幂!
b>>=1;
}
return MOD(ans,c);//答案也要!
}
long long f(long long b,long long mm)
{
if(mm==1)
return MOD(a,1);//模数为1时停止计算,因为之后的结果都是相同的
if(b==1)
{
return MOD(a,mm);//最后一层的情况
}
return qsm(a,f(b-1,phi(mm)),mm);//递归调用
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&a,&b,&m);
if(b==0 || a==1 || m==1)//特殊情况直接输出
{
printf("%lld\n",1%m);
continue;
}
if(b==1)//特殊情况直接输出
{
printf("%lld\n",a%m);
continue;
}
long long ans=f(b,m)%m;
printf("%lld\n",ans);
}
}
后记
昨天比赛时没能想到快速幂回溯,然后就是无尽的WA…,主要还是菜。
除了从外到内的递归法外,这题其实还可以从内到外来做,不容易错,有兴趣的读者可以尝试。
当然,这题也可以推广到更一般的问题:求
,只要将上面的代码微调即可。
最后的最后,感谢一波赛后蔡队一针见血的指点。CSLNB!
DrGilbert 2019.9.2