HDU5728 PowMod(积性函数+扩欧)
(本题解由 ljw 提供 )
题意:定义 k = ∑ i = 1 m φ ( i ∗ n ) m o d 1000000007 k=\sum^{m}_{i=1}\varphi(i*n) mod 1000000007 k=∑i=1mφ(i∗n)mod1000000007,且 n n n是一个无平方因子数, φ ( n ) \varphi(n) φ(n)是欧拉函数,计算 a n s = k k k k . . . k m o d p ans=k^{k^{k^{k^{...^{k}}}}} mod p ans=kkkk...kmodp
范围: 1 ≤ n , m , p ≤ 1 0 7 1 \le n, m, p \le 10^7 1≤n,m,p≤107
分析:欧拉函数简介:
φ ( n ) \varphi(n) φ(n)是欧拉函数,意义为在 1 − n 1-n 1−n的范围内,与 n n n互质的数有多少个,例如 φ ( 2 ) = 1 , φ ( 4 ) = 2 \varphi(2) = 1, \varphi(4) = 2 φ(2)=1,φ(4)=2.
那么很容易可以发现当 n n n为质数时 φ ( n ) = n − 1 \varphi(n) = n - 1 φ(n)=n−1,当 n n n为合数时,我们实际上只需要求出它的所有素因子将 n n n分解为 ( p 1 a 1 ) ∗ ( p 2 a 2 ) ∗ … … ∗ ( p k a k ) (p_{1}^{a_1})*(p_2^{a_2})*……*(p_k^{a_k}) (p1a1)∗(p2a2)∗……∗(pkak),那么 φ ( n ) = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ … … ∗ ( 1 − 1 p k ) \varphi(n) = n*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*……*(1-\frac{1}{p_k}) φ(n)=n∗(1−p11)∗(1−p21)∗……∗(1−pk1)(看不懂的可以去复习一下鸽巢原理)。
积性函数简介:
如果一个数论函数 f ( n ) f(n) f(n)满足 f ( p q ) = f ( p ) f ( q ) , p ⊥ q f(pq)=f(p)f(q),p\perp q f(pq)=f(p)f(q),p⊥q,则称 f ( n ) f(n) f(n)是一个积性函数。特别的,如果不要求 p ⊥ q p\perp q p⊥q且依然满足上述式子的话,则称 f ( n ) f(n) f(n)是一个完全积性函数。例如 f ( x ) = x f(x)=x f(x)=x,便是完全积性函数。( p ⊥ q p \perp q p⊥q指 g c d ( p , q ) = 1 gcd(p,q)=1 gcd(p,q)=1)
常见的积性函数有:
e ( n ) = [ n = 1 ] e(n)=[n=1] e(n)=[n=1],
1 ( n ) = 1 1(n)=1 1(n)=1,
μ ( n ) = { ( − 1 ) k n = p 1 p 2 p 3 … p k 0 n = p 2 q \mu(n)=\begin{cases}(-1)^k&n=p_1p_2p_3\dots p_k\\0&n=p^2q\end{cases} μ(n)={(−1)k0n=p1p2p3…pkn=p2q,
φ ( n ) = ∑ i = 1 n [ i ⊥ n ] \varphi(n)=\sum_{i=1}^n[i\perp n] φ(n)=∑i=1n[i⊥n],
d ( n ) = ∑ i ∣ n 1 d(n)=\sum_{i|n}1 d(n)=∑i∣n1,
i d ( n ) = n id(n)=n id(n)=n,
σ ( n ) = ∑ d ∣ n d \sigma(n)=\sum_{d|n}d σ(n)=∑d∣nd
其他还有一些扩展性知识可以网上搜索了解。
回到本题,可以看出欧拉函数就是一个典型的积性函数,且题目告诉我们 n n n为无平方因子数,则我们可以得到 n = ∏ i = 1 k p i n=\prod_{i=1}^{k}p_i n=∏i=1kpi。因为 φ ( n ) = φ ( n p ) ∗ φ ( p ) ( n p ⊥ p ) \varphi(n) = \varphi(\frac{n}{p})*\varphi(p)(\frac{n}{p} \perp p) φ(n)=φ(pn)∗φ(p)(pn⊥p),所以我们可以将 ∑ i = 1 m φ ( i ∗ n ) \sum^{m}_{i=1}\varphi(i*n) ∑i=1mφ(i∗n)化为 ∑ i = 1 ∩ i ⊥ p m φ ( i ∗ n p ) ∗ φ ( p ) + ∑ i = 1 m p φ ( i ∗ p ∗ n ) \sum^{m}_{i=1\cap i \perp p}\varphi(i* \frac{n}{p})*\varphi(p) + \sum^{\frac{m}{p}}_{i=1}\varphi(i*p*n) ∑i=1∩i⊥pmφ(i∗pn)∗φ(p)+∑i=1pmφ(i∗p∗n)。因为 p p p为 n n n的一个素因子,所以 φ ( i ∗ p ∗ n ) = φ ( i ∗ n ) ∗ p \varphi(i*p*n) = \varphi(i*n) * p φ(i∗p∗n)=φ(i∗n)∗p(联系欧拉函数计算公式理解)。
继续化简可得 φ ( p ) ∗ ∑ i = 1 ∩ i ⊥ p m φ ( i ∗ n p ) + ∑ i = 1 m p φ ( i ∗ n ) ∗ ( φ ( p ) + 1 ) \varphi(p) * \sum^{m}_{i=1\cap i \perp p}\varphi(i* \frac{n}{p})+ \sum^{\frac{m}{p}}_{i=1}\varphi(i*n)*(\varphi(p) + 1) φ(p)∗∑i=1∩i⊥pmφ(i∗pn)+∑i=1pmφ(i∗n)∗(φ(p)+1)。
进行分配律可得 φ ( p ) ∗ ∑ i = 1 ∩ i ⊥ p m φ ( i ∗ n p ) + φ ( p ) ∗ ∑ i = 1 m p φ ( i ∗ n ) + ∑ i = 1 m p φ ( i ∗ n ) ) \varphi(p) * \sum^{m}_{i=1\cap i \perp p}\varphi(i* \frac{n}{p})+ \varphi(p)*\sum^{\frac{m}{p}}_{i=1}\varphi(i*n) + \sum^{\frac{m}{p}}_{i=1}\varphi(i*n)) φ(p)∗∑i=1∩i⊥pmφ(i∗pn)+φ(p)∗∑i=1pmφ(i∗n)+∑i=1pmφ(i∗n))
可以发现,第二项就是第一项所缺少的部分,所以可得 φ ( p ) ∗ ∑ i = 1 m φ ( i ∗ n p ) + ∑ i = 1 m p φ ( i ∗ n ) ) \varphi(p) * \sum^{m}_{i=1}\varphi(i* \frac{n}{p}) + \sum^{\frac{m}{p}}_{i=1}\varphi(i*n)) φ(p)∗∑i=1mφ(i∗pn)+∑i=1pmφ(i∗n))。
到这里我们就已经完成前半个题目的解答,因为每一项都可以看成将题目的范围变化后求解相同的问题,所以得到 n n n的所有素因子之后一个递归即可解决问题。
之后便是计算最终答案。
扩展欧拉定理介绍:
结论: a c ≡ { a c M o d ϕ ( m ) gcd ( a , m ) = 1 a c gcd ( a , m ) ≠ 1 ∧ c < ϕ ( m ) a c M o d ϕ ( m ) + ϕ ( m ) gcd ( a , m ) ≠ 1 ∧ c ≥ ϕ ( m ) a^c~\equiv~\begin{cases}a^{c~Mod~\phi(m)} &\gcd(a,m)~=~1 \\a^c &\gcd(a,m)~\neq~1~\land~c~<~\phi(m) \\ a^{c~Mod~\phi(m)~+~\phi(m)} &\gcd(a,m)~\neq~1~\land~c~\geq~\phi(m)\end{cases} ac ≡ ⎩⎪⎨⎪⎧ac Mod ϕ(m)acac Mod ϕ(m) + ϕ(m)gcd(a,m) = 1gcd(a,m) = 1 ∧ c < ϕ(m)gcd(a,m) = 1 ∧ c ≥ ϕ(m)
证明可看这篇blog。
利用这个定理,我们可以循环求解幂的情况,因为每次将幂向上一层,我们的模数都会变成原先的模数的欧拉函数,所以必然比原先的模数小,所以这个模数最终会变成 1 1 1,即在一定程度上,无限幂次在取模的意义下和某一有限幂次是等价的。所以即可解决这个问题。
Code:
#include<bits/stdc++.h>
#define N 10000010
#define ll long long
using namespace std;
bool vis[N];
int phi[N];
long long sum2[N];
int cnt,prim[N];
const long long mod = 1000000007;
// 线性筛处理出所有素数以及欧拉函数值以及欧拉函数前缀和
void get(int maxn)
{
phi[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
{
prim[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&prim[j]*i<=maxn;j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
else phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
for(int i=1;i<=maxn;i++)sum2[i]=(sum2[i-1]+phi[i]);
}
struct P {
ll ans;
bool v;
P(ll _ans, bool _v) {
ans = _ans;
v = _v;
}
};
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
// 扩欧中的快速幂细节处理
P qpow(ll A, ll B, ll C) {
ll re = 1;
bool flag = 1;
while(B) {
if(B & 1) {
if((re *= A) >= C) flag = 0;
re = re % C;
}
B = B >> 1;
if(B) {
if(A >= C) flag = 0;
A %= C;
if((A *= A) >= C) flag = 0;
A %= C;
}
}
return P(re, flag);
}
// 扩欧计算第二步
P f(ll a, ll b, ll k, ll p) {
if(p == 1) return P(0, 0);
if(k == 0) return P(a % p, a < p);
ll ep = phi[p];
P tmp = f(b, b, k-1, ep);
if(gcd(a, p) == 1)return qpow(a, tmp.ans, p);
if(tmp.v == false) {
tmp.ans += ep;
}
return qpow(a, tmp.ans, p);
}
// 迭代计算第一步,也可以预先处理出所有素因子
ll g(ll n,ll m)
{
if(n == 1) return sum2[m] % mod;
if(m == 1) return phi[n];
if(m == 0) return 0;
if(phi[n] == n - 1){
return (phi[n] * g(1, m) % mod + g(n, m / n)) % mod;
}
int p = sqrt(n) + 1;
for(int i = 1; i <= cnt && prim[i] <= p; ++i){
if(!(n % prim[i]))
return (phi[prim[i]] * g(n / prim[i], m) % mod + g(n, m / prim[i])) % mod;
}
}
int main()
{
int n, m, p;
get(10000000);
while(~scanf("%d %d %d", &n, &m, &p)){
long long k = g(n, m);
printf("%lld\n", f(k, k, 100000000, p).ans);
}
return 0;
}
【END】感谢观看