感觉智商被掏空…
原题见HDU 5728
定义
k=∑mi=1φ(i·n) mod 1000000007
n
是无质因子平方项的数.
求
数据范围:
1≤n,m,p≤107
各种引理
- 若素数p满足 p2∣n ,则 φ(n)=p·φ(np) 见性质3
- 若素数p满足 p∣n, p2∤n ,则 φ(n)=(p−1)·φ(np)
-
ab≡aφ(p)+b%φ(p)(modp)
当 gcd(a,p)=1 ,有欧拉定理 aφ(p)≡1(modp) ,等式成立。
当 gcd(a,p)=g>1 ,只要证 aφ(p)≡a2φ(p)(modp) ,即可得到 aφ(p)≡aφ(p)的任意多倍
只要证 aφ(p)(aφ(p)−1)=p的倍数(∗)
令 a=gx,p=gy,则gcd(x,y)=1 ,有 g∣aφ(p)
又 φ(y)∣φ(p),则y∣aφ(y)−1∣aφ(p)−1 即证(*)成立。
aφ(p)≡0或1(modp)
分析
题意很清晰啦。数据范围这么大,肯定要先化简。
n
是无质因子平方项的数.这个条件很关键,说明任取n中的因子g,满足
取i,满足
gcd(i,n)=g
,则
gcd(ig,ng)=1
,综合
(∗)可得gcd(g2×ig,ng)=1
则由
φ(i·n)=φ(i·g·ng)=φ(i·g)φ(ng)
又
g∣i
,则
φ(i·g)=g·φ(i)
然后…莫比乌斯反演展开…并没有什么卵用
所以看了题解,不按套路啊…
任取n中的质数p,若
p∣i
,则
p2∣i·n
,则由引理1:
φ(i·n)=p·φ(i·np)
若
p∤i
,则
p2∤i·n
,则由引理2:
φ(i·n)=(p−1)φ(i·np)
令 S(n,m)=∑i=1mφ(i·n) ,则
处理一下欧拉函数前缀和,递归处理即可。
已经询问过的S(n,m)可以保存在
map<pair<n,m>, S>
里,不用反复查询。
然后看看
ans=kkkk...k( mod p)
两种错误的想法,样例都不能过,不想清楚还是很抓狂…
认为
ans=kans( mod p)
或者
ans=ansk( mod p)
的,就不要玩了。
一般情况下,
ax≢ax%p(modp)
令
A(k,p)=kkkk...k( mod p)
由引理3,
kb≡kφ(p)+b%φ(p)(modp)
,
b=kkkk...k
,可得
代码
#include <bits/stdc++.h>
using namespace std;
#define N 10000010
#define LL long long
int MOD = 1000000007;
int num[N], prim[N], phi[N], sum[N];
int pn = 0;
void init(){
memset(num, -1, sizeof(num));
phi[0] = phi[1] = 1;
for(int i = 2;i < N;i++){
if(num[i]){
prim[pn++] = i;
phi[i] = i-1;
}
for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){
if(i % prim[j] == 0){
phi[i*prim[j]] = phi[i] * prim[j];
num[i*prim[j]] = 0;
break;
}
phi[i*prim[j]] = phi[i] * (prim[j] - 1);
num[i*prim[j]] = 0;
}
}
sum[0] = 0;
for(int i = 1;i < N;i++)
sum[i] = 1LL*(sum[i-1] + phi[i]) % MOD;
}
int s(int n, int m){
if(n == 1)
return sum[m];
if(m == 0)
return 0;
for(int i = 0;i < pn && prim[i] <= n;i++){
if(n % prim[i] == 0){
int p = prim[i];
return (1LL*(p-1)*s(n/p, m)%MOD + s(n, m/p)%MOD)%MOD;
}
}
}
LL poo(LL a, int k, int m){
LL res = 1;
while(k){
if(k & 1LL) res = res*a%m;
k >>= 1;
a = a*a%m;
}
return res;
}
int A(int k, int p){
if(p == 1) return 0;
if(k == 1) return 1;
return poo(1LL*k%p, phi[p]+A(k, phi[p]), p);
}
int main(){
init();
int n, m, p;
while(~scanf("%d%d%d", &n, &m, &p)){
int k = s(n, m);
int ans = A(k, p);
printf("%d\n", ans);
}
return 0;
}