HDU5728 PowMod(积性函数+扩欧)

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φ(in)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 1n,m,p107

分析:欧拉函数简介:

φ ( n ) \varphi(n) φ(n)是欧拉函数,意义为在 1 − n 1-n 1n的范围内,与 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)=n1,当 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(1p11)(1p21)(1pk1)(看不懂的可以去复习一下鸽巢原理)。

积性函数简介:

如果一个数论函数 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),pq,则称 f ( n ) f(n) f(n)是一个积性函数。特别的,如果不要求 p ⊥ q p\perp q pq且依然满足上述式子的话,则称 f ( n ) f(n) f(n)是一个完全积性函数。例如 f ( x ) = x f(x)=x f(x)=x,便是完全积性函数。( p ⊥ q p \perp q pq 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=p1p2p3pkn=p2q,

φ ( n ) = ∑ i = 1 n [ i ⊥ n ] \varphi(n)=\sum_{i=1}^n[i\perp n] φ(n)=i=1n[in],

d ( n ) = ∑ i ∣ n 1 d(n)=\sum_{i|n}1 d(n)=in1,

i d ( n ) = n id(n)=n id(n)=n,

σ ( n ) = ∑ d ∣ n d \sigma(n)=\sum_{d|n}d σ(n)=dnd

其他还有一些扩展性知识可以网上搜索了解。

回到本题,可以看出欧拉函数就是一个典型的积性函数,且题目告诉我们 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)(pnp),所以我们可以将 ∑ i = 1 m φ ( i ∗ n ) \sum^{m}_{i=1}\varphi(i*n) i=1mφ(in)化为 ∑ 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=1ipmφ(ipn)φ(p)+i=1pmφ(ipn)。因为 p p p n n n的一个素因子,所以 φ ( i ∗ p ∗ n ) = φ ( i ∗ n ) ∗ p \varphi(i*p*n) = \varphi(i*n) * p φ(ipn)=φ(in)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=1ipmφ(ipn)+i=1pmφ(in)(φ(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=1ipmφ(ipn)+φ(p)i=1pmφ(in)+i=1pmφ(in))

可以发现,第二项就是第一项所缺少的部分,所以可得 φ ( 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φ(ipn)+i=1pmφ(in))

到这里我们就已经完成前半个题目的解答,因为每一项都可以看成将题目的范围变化后求解相同的问题,所以得到 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】感谢观看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值