题意:给定p, b(0<=b<p<=10^5)和m(1<=m<2^64),问有多少个n满足n^(n!)=b (mod p)。
思路:首先要知道这个结论:
当n!<Phi(C)时,此时我们暴力解决就可。
当n!大于phi(P)的时候,就需要用上面的降幂公式了。
方法还是暴力,n!%phi(p)会出现0,这是必然的,至少n>=phi(p)为0,
那么(n+1)!%phi(p)也为0,这便出现了重复,转变为n^(phi(p))%p==b的问题了。
固定了指数,根据鸽巢原理,余数是循环的,那么只要找出p个的结果,之后通过循环节求解便可以了。
Trick:当P为1的时候,b为0,这时候答案是m+1,不过m可能为2^64-1,如果加1的话就会溢出。
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=1e5+50;
ll arr[maxn];
ll eular(ll n)
{
ll res=n;
for(ll i=2;i*i<=n;i++)
{
if(n%i==0)
{
res=res-res/i;
while(n%i==0)
{
n/=i;
}
}
}
if(n>1)
{
res=res-res/n;
}
return res;
}
ll power(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
int cas=0;
while(t--)
{
ll b,p,m;
scanf("%llu%llu%llu",&b,&p,&m);
printf("Case #%d: ",++cas);
if(p==1)
{
if(m==18446744073709551615ll)
printf("18446744073709551616\n");
else
printf("%llu\n",m+1);
continue;
}
ll ph=eular(p);
ll fac=1;
ll i;
ll ans=0;
for(i=0;i<=m&&fac<ph;i++)
{
if(power(i,fac,p)==b)
ans++;
fac=fac*(i+1);
}
fac%=ph;
for(;i<=m&&fac;i++)
{
if(power(i,fac+ph,p)==b)
{
ans++;
}
fac=(fac*(i+1))%ph;
}
if(i<=m)
{
ll cnt=0;
for(ll j=0;j<p;j++)
{
arr[j]=power(i+j,ph,p);
if(1ll*power(i+j,ph,p)==b)
{
cnt++;
}
}
ll num=(m-i+1)/p;// 循环节长度
ans+=num*cnt;
num=(m-i+1)%p;// 剩余部分
for(ll j=0;j<num;j++)// 这里是开区间 因为num等于0时说明正好能整除 故不进行操作
{
if(arr[j]==b)
{
ans++;
}
}
}
printf("%llu\n",ans);
}
return 0;
}