is a square-free number. 他是一个无平方因子数。也就是说他分解质因子后质因子的指数是1.
解决这个题分两步,先说第二步,第二步是 bzoj 3884原题,只是在这个题我们需要算底数是多少而已。
引用一下别人的证明(本人巨菜)
考虑欧拉定理,当
(a,p)=1
时,
aϕ(p)≡1(modp)
。
而由此可以很容易得出一个结论:
当
x≥ϕ(p)
时,有
若令
f(p)=222...modp
,则
f(1)=0
。
又由于是无穷的式子,
222...
的指数本来就是超过
ϕ(p)
的,所以我们可以改写成
因而得到了 f(p) 的递推式。
似乎这么计算是
O(p)
的,但是我们可以对
ϕ(ϕ(...ϕ(p)))
进行分析:
若
p
为偶数,则
ϕ(p)≤p2
;
若
p
为奇数,则
p
存在一个奇数因子
q
,使得
ϕ(p)
存在一个偶数因子
(q−1)
,转化为偶数的情况。
由此可知,
ϕ(ϕ(...ϕ(p)))
的计算经过
O(logp)
次的迭代就到了
1
,所以
f(p)
的计算是
O(p√logp)
的。
然后我们来到第一步:解决这个问题,我们需要知道几个性质
对于质数p,φ(p) = p - 1。注意φ(1)=1.
欧拉定理:对于互质的正整数a和n,有aφ(n) ≡ 1 mod n。
欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。
若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。
因为此题时间的限制,我们只能筛选10^7以内的所有素数,在求素数的时候顺便就求出欧拉函数,再求出前n项和。
我们来看,如果m是10^7次方,n也是10^7(当然n不可能是10^7),那么我们就希望看能不能把这个i*n的数字变小,变小就有两个方法,把n变小,把m变小。
对于φ (i*n)来说,我们可以令n=x*pri,对于i*n的欧拉值就是求φ(i*x*pri),如果pri和i互质,就是积性的,就可以把pri提出去,φ(i*x)*(pri-1);如果i有因子p的话,我们就可以把m缩小,让m/p为上线, 不变n。依次递推。
当m等于1的时候,那么最终的值就是n的欧拉函数值,当n等于1的时候,就是前m个的欧拉函数值的和。
最方便的情况是先把n素因子分解,然后一个一个用就是咯。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e7;
const int maxm=1e5*7;
ll prime[maxm+10];
bool isprime[maxn+10];
ll phi[maxn+10];
ll sphi[maxn+10];
ll index[50];
//ll sphi[maxn+10];
int cnt;
map<ll,ll>mp;
int res;
void init()
{
cnt=0;
phi[1]=1;
sphi[1]=1;
for(ll i=2; i<=maxn; i++)
{
if(!isprime[i])
{
prime[cnt++]=i;
phi[i]=i-1;
}
for(ll j=0; j<cnt&&i*prime[j]<=maxn; j++)
{
isprime[i*prime[j]]=true;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
sphi[i]=(sphi[i-1]+phi[i])%mod;
}
}
ll n,m;
ll p;
ll k;
ll mul(ll a,ll b,ll o)
{
ll ans=1;
while(b)
{
if(b&1)
ans=(ans*a)%o;
b>>=1;
a=(a*a)%o;
}
return ans;
}
ll Phi(ll x)
{
ll ret = x;
for(ll i = 2; i * i <= x; ++i)
if(x % i == 0)
{
ret -= ret / i;
while(x % i == 0)
x /= i;
}
if(x > 1)
ret -= ret / x;
return ret;
}
ll f(ll x)
{
if(mp.count(x))
return mp[x];
ll c=phi[x];
return mp[x]=(mul(k,f(c)+c,x))%x;
}
ll sovle(int id,ll n,ll m)
{
// printf("%d %lld %lld\n",id,n,m);
// getchar();
// if(m==1)
// return phi[n];
// //printf("sssss");
if(n==1)
return sphi[m];
if(m==0)
return 0;
if(id==-1)///没有什么用,因为测不合法的数据要停止工作,不爽
return 0;
return ((sovle(id-1,n/index[id],m)*(index[id]-1))%mod+sovle(id,n,m/index[id]))%mod;
}
void fen(ll n)
{
//printf("%d\n",cnt);
for(int i=0; i<cnt; i++)
{
if(!isprime[n])
{
index[res++]=n;
break;
}
if(n%prime[i]==0)
{
index[res++]=prime[i];
n/=prime[i];
}
}
}
int main()
{
init();
//printf("%d\n",cnt);
//cout<<sphi[5]<<endl;
while(~scanf("%lld%lld%lld",&n,&m,&p))
{
mp.clear();
k=0;
res=0;
fen(n);
res--;
//printf("%d\n",res);
k=(k+sovle(res,n,m))%mod;
// printf("%lld\n",k);
printf("%lld\n",f(p));
}
}