HDU 5728 PowMod (16多校第一场)

题意

$k=\sum_{i=1}^{m} \varphi (i*n) mod 1000000007$
$n$ is a square-free number. 一个无平方因子数,质因子的指数是1
$\varphi $ is the Euler’s totient function.

find: $ans=k^{k^{k^{k^{…^k}}}} mod p$

分析

  • 这题看题解看了老半天
    • 第一步
      计算每一个$p _j$对n的贡献得出:$f(n,m)=ϕ(pj)∗f(\frac n{p _j},m)+f(n,\frac m {p _j})$
    • 第二步
      利用上面公式不断递归得出k的值,递归终点是f(1,y)或者f(x,1)以及f(x,0);
    • 第三步
      利用公式$a ^b \%p=a ^{b \% ϕ(p)+ϕ(p) }\%p$,一直递归到p=0
  • 附送线性筛法传送门
  • 欧拉函数是积性函数,给出一些欧拉函数性质

    • 设a为N的质因数
      (N%a == 0 && (N / a) % a == 0)
      则有E(N)=E(N / a) * a
      (N % a == 0 && (N / a) % a != 0)
      则有:E(N) = E(N / a) * (a - 1)
    • 当n为奇数时,φ(2n)=φ(n)
    • 若n是质数p的k次幂
      φ(n)=p^k-p^(k-1)=(p-1)p^(k-1)
      因为除了p的倍数外,其他数都跟n互质。
    • 若m,n互质
      φ(mn)=φ(m)φ(n)
  • 欧拉定理:对于互质的正整数a和n,有aφ(n) ≡ 1 mod n。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*************************************************************************
> File Name: f.cpp
> Author: liangxianfeng
> Mail: liangxianfeng96@qq.com
> Created Time: 2016年07月22日 星期五 15时04分33秒
************************************************************************/


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<string>
#include<cmath>
using namespace std;
#define ll long long
#define rep(i,n) for(int i =0; i < n; ++i)
#define CLR(x) memset(x,0,sizeof x)
#define MEM(a,b) memset(a,b,sizeof a)
#define pr(x) cout << #x << " = " << x << " ";
#define prln(x) cout << #x << " = " << x << endl;
const int maxn = 1e7+5;
const int INF = 0x3f3f3f3f;
int phi[maxn], prime[maxn];
const int MOD = 1e9+7;
bool vis[maxn];
int pt;
ll sum[maxn];
void init(){
int k = 0;
pt = 0;

phi[1] = 1;
for(int i = 2; i < maxn; ++i){
if(!vis[i]){
phi[i] = i-1;
prime[pt++] = i;
//prln(i);
//if(i>100) break;
}
for(int j = 0; j < pt ; ++j){
k = prime[j]*i;
if(k>=maxn) break;
vis[k] = true;
if(i%prime[j] == 0){
phi[k] = phi[i] * prime[j];
break;
}
else{
phi[k] = phi[i] * (prime[j]-1);
}
}
}
sum[0] = 0;
for(int i = 1; i < maxn; ++i){
sum[i] = (sum[i-1] + phi[i])%MOD;
}
}
ll getans(int n, int m){
if(n == 1) return sum[m];
if(m == 1) return phi[n];
if(m < 1) return 0;
for(int i = 0; i < pt; ++i){
if(n%prime[i] == 0){
return ((prime[i]-1)*getans(n/prime[i], m)%MOD + getans(n, m/prime[i]))%MOD;
}
}
}
ll ret(ll x, ll y, int p){
ll ans = 1;
x%=p;
//prln(p);
while(y){
if(y&1)ans = ans*x%p;
//pr(x);pr(y);pr(ans);prln(MOD);
x = x*x%p;
y >>= 1;
}
return ans;
}
ll getpow(ll k, int p){
if(p == 1) return 0;
ll tmp = getpow(k, phi[p]);
return ret(k, tmp+phi[p], p);
}
int main(){
#ifdef LOCAL
freopen("/home/zeroxf/桌面/in.txt","r",stdin);
//freopen("/home/zeroxf/桌面/out.txt","w",stdout);
#endif
init();
int n, m, p;
while(scanf("%d%d%d", &n, &m, &p) != EOF){
ll k = getans(n,m);
printf("%lld\n",getpow(k,p));
}
return 0;
}