题意:
给你n , m , m o d n,m,mod n , m , m o d 让你求∏ i = 1 n ∏ j = 1 n ∏ k = 1 n m gcd ( i , j ) [ k ∣ gcd ( i , j ) ] % m o d \prod\limits_{i=1}^{n}\prod\limits_{j=1}^{n}\prod\limits_{k=1}^{n}m^{\gcd(i,j)[k|\gcd(i,j)]}\%\ mod i = 1 ∏ n j = 1 ∏ n k = 1 ∏ n m g cd( i , j ) [ k ∣ g cd( i , j ) ] % m o d
思路:
由于相乘的的公式不好化,我们可以先把次幂提出来这样就把公式化成这样m ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n gcd ( i , j ) [ k ∣ g c d ( i , j ) ] % φ ( m o d ) % m o d m^{\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}\gcd(i,j)[k|gcd(i,j)]\%\varphi(mod)}\%\ mod m i = 1 ∑ n j = 1 ∑ n k = 1 ∑ n g cd( i , j ) [ k ∣ g c d ( i , j ) ] % φ ( m o d ) % m o d
因为对指数求和取模,所以要用到欧拉降幂,因为m o d mod m o d 是素数所以直接对φ ( m o d ) \varphi(mod) φ ( m o d ) 取模即可
那么我们的任务就变成了化简∑ i = 1 n ∑ j = 1 n ∑ k = 1 n gcd ( i , j ) [ k ∣ g c d ( i , j ) ] % φ ( m o d ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}\gcd(i,j)[k|gcd(i,j)]\%\varphi(mod) i = 1 ∑ n j = 1 ∑ n k = 1 ∑ n g cd( i , j ) [ k ∣ g c d ( i , j ) ] % φ ( m o d )
我们把g c d gcd g c d 提出来后
∑ g = 1 n g ∑ k = 1 n [ k ∣ g ] ∑ i = 1 n / g ∑ j = 1 n / g [ gcd ( i , j ) = = 1 ] \sum\limits_{g=1}^{n}g\sum\limits_{k=1}^{n}[k|g]\sum\limits_{i=1}^{n/g}\sum\limits_{j=1}^{n/g}[\gcd(i,j) == 1] g = 1 ∑ n g k = 1 ∑ n [ k ∣ g ] i = 1 ∑ n / g j = 1 ∑ n / g [ g cd( i , j ) = = 1 ]
∑ g = 1 n g ∑ k ∣ g ∑ i = 1 n / g ∑ j = 1 n / g [ gcd ( i , j ) = = 1 ] \sum\limits_{g=1}^{n}g\sum\limits_{k|g}\sum\limits_{i=1}^{n/g}\sum\limits_{j=1}^{n/g}[\gcd(i,j) == 1] g = 1 ∑ n g k ∣ g ∑ i = 1 ∑ n / g j = 1 ∑ n / g [ g cd( i , j ) = = 1 ]
把k k k 提到外面
∑ k = 1 n k ∑ g = 1 n / k g ∑ i = 1 n / g k ∑ j = 1 n / g k [ gcd ( i , j ) = = 1 ] \sum\limits_{k=1}^{n}k\sum\limits_{g=1}^{n/k}g\sum\limits_{i=1}^{n/gk}\sum\limits_{j=1}^{n/gk}[\gcd(i,j) == 1] k = 1 ∑ n k g = 1 ∑ n / k g i = 1 ∑ n / g k j = 1 ∑ n / g k [ g cd( i , j ) = = 1 ]
后面的根据莫比乌斯反演
∑ k = 1 n k ∑ g = 1 n / k g ∑ i = 1 n / k g ∑ j = 1 n / k g ∑ d ∣ g c d ( i , j ) μ ( d ) \sum\limits_{k=1}^{n}k\sum\limits_{g=1}^{n/k}g\sum\limits_{i=1}^{n/kg}\sum\limits_{j=1}^{n/kg}\sum\limits_{d|gcd(i,j)}\mu(d) k = 1 ∑ n k g = 1 ∑ n / k g i = 1 ∑ n / k g j = 1 ∑ n / k g d ∣ g c d ( i , j ) ∑ μ ( d )
我们在把μ \mu μ 提到外面
∑ k = 1 n k ∑ g = 1 n / k g ∑ d = 1 n / k g μ ( d ) ∑ i = 1 n / k g d ∑ j = 1 n / k g d 1 \sum\limits_{k=1}^{n}k\sum\limits_{g=1}^{n/k}g\sum\limits_{d=1}^{n/kg}\mu(d)\sum\limits_{i=1}^{n/kgd}\sum\limits_{j=1}^{n/kgd}1 k = 1 ∑ n k g = 1 ∑ n / k g d = 1 ∑ n / k g μ ( d ) i = 1 ∑ n / k g d j = 1 ∑ n / k g d 1
∑ k = 1 n k ∑ g = 1 n / k g ∑ d = 1 n / k g μ ( d ) ⌊ n k d g ⌋ 2 \sum\limits_{k=1}^{n}k\sum\limits_{g=1}^{n/k}g\sum\limits_{d=1}^{n/kg}\mu(d)\lfloor\frac{n}{kdg}\rfloor^2 k = 1 ∑ n k g = 1 ∑ n / k g d = 1 ∑ n / k g μ ( d ) ⌊ k d g n ⌋ 2
我们令T = k d g T=kdg T = k d g
∑ T = 1 n ⌊ n T ⌋ 2 ∑ k ∣ T k ∑ d ∣ T k d ⋅ μ ( T k d ) \sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor^2\sum\limits_{k|T}k\sum\limits_{d|\frac{T}{k}}d \cdot \mu(\frac{T}{kd}) T = 1 ∑ n ⌊ T n ⌋ 2 k ∣ T ∑ k d ∣ k T ∑ d ⋅ μ ( k d T )
后面的∑ k ∣ T k ∑ d ∣ T k d ⋅ μ ( T k d ) \sum\limits_{k|T}k\sum\limits_{d|\frac{T}{k}}d\cdot \mu(\frac{T}{kd}) k ∣ T ∑ k d ∣ k T ∑ d ⋅ μ ( k d T ) 为I d ∗ I d ∗ μ ( ∗ 为 迪 利 克 雷 卷 积 ) Id*Id*\mu(*为迪利克雷卷积) I d ∗ I d ∗ μ ( ∗ 为 迪 利 克 雷 卷 积 )
因为I d ∗ μ = φ Id*\mu=\varphi I d ∗ μ = φ
所以原式可以化成∑ T = 1 n ⌊ n T ⌋ 2 ∑ k ∣ T k ⋅ φ ( T k ) \sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor^2\sum\limits_{k|T}k \cdot \varphi(\frac{T}{k}) T = 1 ∑ n ⌊ T n ⌋ 2 k ∣ T ∑ k ⋅ φ ( k T )
我们令F ( n ) = ∑ k ∣ n k ⋅ φ ( T k ) F(n)=\sum\limits_{k|n}k\cdot \varphi(\frac{T}{k}) F ( n ) = k ∣ n ∑ k ⋅ φ ( k T )
因为F ( n ) = I d ∗ φ F(n) = Id * \varphi F ( n ) = I d ∗ φ
那么我们把F ( n ) 卷 积 上 一 个 g ( n ) = 1 后 F(n)卷积上一个g(n)=1后 F ( n ) 卷 积 上 一 个 g ( n ) = 1 后
F ∗ g = I d ∗ φ ∗ 1 = I d ∗ I d = ∑ k ∣ n k ⋅ n k = ∑ k ∣ n n F*g=Id*\varphi *1=Id*Id=\sum\limits_{k|n}k\cdot \frac{n}{k}=\sum\limits_{k|n}n F ∗ g = I d ∗ φ ∗ 1 = I d ∗ I d = k ∣ n ∑ k ⋅ k n = k ∣ n ∑ n
那么F ( n ) 的 前 缀 和 就 可 以 用 杜 教 筛 F(n)的前缀和就可以用杜教筛 F ( n ) 的 前 缀 和 就 可 以 用 杜 教 筛
g ( 1 ) S ( n ) = ∑ i = 1 n ∑ k ∣ i i − ∑ i = 2 n S ( ⌊ n i ⌋ ) g(1)S(n)=\sum\limits_{i=1}^{n}\sum\limits_{k|i}i-\sum\limits_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor) g ( 1 ) S ( n ) = i = 1 ∑ n k ∣ i ∑ i − i = 2 ∑ n S ( ⌊ i n ⌋ )
对于∑ i = 1 n ∑ k ∣ i i \sum\limits_{i=1}^{n}\sum\limits_{k|i}i i = 1 ∑ n k ∣ i ∑ i
我们把k k k 提到前面 ∑ i = 1 n i ∑ j = 1 n / i j , 这 样 可 以 用 分 块 快 速 求 出 结 果 \sum\limits_{i=1}^{n}i\sum\limits_{j=1}^{n/i}j,这样可以用分块快速求出结果 i = 1 ∑ n i j = 1 ∑ n / i j , 这 样 可 以 用 分 块 快 速 求 出 结 果
那么杜教筛就为S ( n ) = ∑ i = 1 n i ∑ j = 1 n / i j − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n)=\sum\limits_{i=1}^{n}i\sum\limits_{j=1}^{n/i}j-\sum\limits_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor) S ( n ) = i = 1 ∑ n i j = 1 ∑ n / i j − i = 2 ∑ n S ( ⌊ i n ⌋ )
原式为:∑ T = 1 n ⌊ n T ⌋ 2 F ( T ) \sum\limits_{T=1}^{n}\lfloor\frac{n}{T}\rfloor^2F(T) T = 1 ∑ n ⌊ T n ⌋ 2 F ( T )
当T ≤ n 2 3 F ( n ) 为 ∑ k ∣ n k ⋅ φ ( n k ) T\leq n^{\frac{2}{3}} F(n)为\sum\limits_{k|n}k\cdot \varphi(\frac{n}{k}) T ≤ n 3 2 F ( n ) 为 k ∣ n ∑ k ⋅ φ ( k n )
当 T ≥ n 2 3 时 F ( n ) 用 杜 教 筛 求 当T\geq n^{\frac{2}{3}}时 F(n) 用杜教筛求 当 T ≥ n 3 2 时 F ( n ) 用 杜 教 筛 求
那么问题来了,怎么快速求∑ k ∣ n k ⋅ φ ( n k ) \sum\limits_{k|n}k\cdot \varphi(\frac{n}{k}) k ∣ n ∑ k ⋅ φ ( k n ) 呢
如果用n l o g ( n ) nlog(n) n l o g ( n ) 那就稳T了
参照这篇博客
我们设G ( p n ) 为 ∑ k ∣ p n k ⋅ φ ( n k ) = ∑ p i ⋅ p j = p n p i ⋅ φ ( p j ) G(p^n)为\sum\limits_{k|p^n}k\cdot \varphi(\frac{n}{k})=\sum\limits_{p^i\cdot p^j=p^n}p^i\cdot \varphi(p^j) G ( p n ) 为 k ∣ p n ∑ k ⋅ φ ( k n ) = p i ⋅ p j = p n ∑ p i ⋅ φ ( p j )
∑ p i ⋅ p j = p n p i ⋅ φ ( p j ) = p 0 ⋅ φ ( p n ) + p 1 ⋅ φ ( p n − 1 ) + p 2 ⋅ φ ( p n − 2 ) + . . . + p n ⋅ φ ( p 0 ) \sum\limits_{p^i\cdot p^j=p^n}p^i\cdot \varphi(p^j)=p^0\cdot \varphi(p^{n})+p^1\cdot \varphi(p^{n-1})+p^2\cdot \varphi(p^{n-2})+...+p^n\cdot \varphi(p^{0}) p i ⋅ p j = p n ∑ p i ⋅ φ ( p j ) = p 0 ⋅ φ ( p n ) + p 1 ⋅ φ ( p n − 1 ) + p 2 ⋅ φ ( p n − 2 ) + . . . + p n ⋅ φ ( p 0 )
因为φ ( x ) = x ∏ i ( 1 − 1 p i ) \varphi(x)=x\prod\limits_{i}(1-\frac{1}{p_i}) φ ( x ) = x i ∏ ( 1 − p i 1 )
带入上式中,得到G ( p n ) = ( n + 1 ) p n − n p n − 1 G(p^n) = (n+1)p^n-np^{n-1} G ( p n ) = ( n + 1 ) p n − n p n − 1
我们定义三个中间变量,
g , p h i , s g, phi, s g , p h i , s
g 代 表 g ( n ) s 代 表 n 最 小 的 质 因 子 p 及 其 指 数 e 的 g ( p e ) p h i 代 表 n 最 小 的 质 因 子 p 及 其 指 数 e 的 φ ( p e ) g代表g(n)\\
s代表n最小的质因子p及其指数e的g(p^e)\\
phi代表n最小的质因子p及其指数e的\varphi(p^e) g 代 表 g ( n ) s 代 表 n 最 小 的 质 因 子 p 及 其 指 数 e 的 g ( p e ) p h i 代 表 n 最 小 的 质 因 子 p 及 其 指 数 e 的 φ ( p e )
那么当我们进行线性筛时,
F[ 1 ] = g[ 1 ] = phi[ 1 ] = 1 ;
for ( ll i = 2 ; i <= maxn; i ++ ) {
if ( ! mark[ i] ) {
prim[ ++ tot] = i;
phi[ i] = i - 1 ;
g[ i] = s[ i] = 2 * i- 1 ;
}
for ( ll j = 1 ; j <= tot; j ++ ) {
if ( i * prim[ j] > maxn) break ;
mark[ i * prim[ j] ] = 1 ;
if ( i % prim[ j] == 0 ) {
s[ i* prim[ j] ] = ( s[ i] + phi[ i] + 0ll ) * prim[ j] ;
phi[ i * prim[ j] ] = phi[ i] * prim[ j] ;
g[ i* prim[ j] ] = g[ i] / s[ i] * s[ i* prim[ j] ] ;
break ;
}
phi[ i * prim[ j] ] = phi[ prim[ j] ] ;
s[ i* prim[ j] ] = s[ prim[ j] ] ;
g[ i* prim[ j] ] = g[ i] * s[ i* prim[ j] ] ;
}
F[ i] = ( F[ i- 1 ] + g[ i] ) % p;
}
根 据 线 性 筛 的 性 质 , 下 面 的 j 是 i ∗ j 这 个 数 的 最 小 质 因 子 根据线性筛的性质,下面的j是i*j这个数的最小质因子 根 据 线 性 筛 的 性 质 , 下 面 的 j 是 i ∗ j 这 个 数 的 最 小 质 因 子
对 于 p h i 当 i 不 包 含 j 时 p h i [ i ∗ j ] = p h i [ j ] 当 i 包 含 j 时 p h i [ i ∗ j ] = p h i [ i ] ∗ j ( 欧 拉 函 数 的 性 质 ) 对于phi\\
当i不包含j时phi[i*j]=phi[j]\\
当i包含j时phi[i*j]=phi[i]*j(欧拉函数的性质) 对 于 p h i 当 i 不 包 含 j 时 p h i [ i ∗ j ] = p h i [ j ] 当 i 包 含 j 时 p h i [ i ∗ j ] = p h i [ i ] ∗ j ( 欧 拉 函 数 的 性 质 )
对 于 s 当 i 不 包 含 j 时 , s [ i ∗ j ] = s [ j ] 当 i 包 含 j 时 , s [ i ∗ j ] = ( s [ i ] + p h i [ i ] ) ∗ j s [ i ] = ( e + 1 ) p e − e ⋅ p e − 1 s [ i ] + p h i [ i ] = ( e + 2 ) p e − ( e + 1 ) ⋅ p e − 1 ( s [ i ] + p h i [ i ] ) ⋅ j = ( e + 2 ) p e + 1 − ( e + 1 ) ⋅ p e 这 样 s [ i ∗ j ] 就 把 j 的 最 小 质 因 子 的 个 数 就 加 了 一 个 对于s\\
当i不包含j时,s[i*j]=s[j]\\
当i包含j时,s[i*j]=(s[i]+phi[i])*j\\
s[i] = (e+1)p^{e} - e \cdot p ^ {e-1}\\
s[i]+phi[i]=(e+2)p^e-(e+1)\cdot p^{e-1}\\
(s[i]+phi[i])\cdot j=(e+2)p^{e+1}-(e+1)\cdot p^{e}\\
这样s[i*j]就把j的最小质因子的个数就加了一个 对 于 s 当 i 不 包 含 j 时 , s [ i ∗ j ] = s [ j ] 当 i 包 含 j 时 , s [ i ∗ j ] = ( s [ i ] + p h i [ i ] ) ∗ j s [ i ] = ( e + 1 ) p e − e ⋅ p e − 1 s [ i ] + p h i [ i ] = ( e + 2 ) p e − ( e + 1 ) ⋅ p e − 1 ( s [ i ] + p h i [ i ] ) ⋅ j = ( e + 2 ) p e + 1 − ( e + 1 ) ⋅ p e 这 样 s [ i ∗ j ] 就 把 j 的 最 小 质 因 子 的 个 数 就 加 了 一 个
对 于 g 根 据 积 性 函 数 的 性 质 当 i 不 包 括 j 时 , g [ i ⋅ j ] = g [ i ] ⋅ s [ i ⋅ j ] 当 i 包 括 j 时 , g [ i ⋅ j ] = g [ i ] / s [ i ] ⋅ s [ i ⋅ j ] 对于g\\
根据积性函数的性质\\
当i不包括j时,g[i\cdot j]=g[i]\cdot s[i\cdot j]\\
当i包括j时,g[i\cdot j]=g[i]/s[i]\cdot s[i\cdot j] 对 于 g 根 据 积 性 函 数 的 性 质 当 i 不 包 括 j 时 , g [ i ⋅ j ] = g [ i ] ⋅ s [ i ⋅ j ] 当 i 包 括 j 时 , g [ i ⋅ j ] = g [ i ] / s [ i ] ⋅ s [ i ⋅ j ]
这样就可以预处理前缀和了
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-8 ;
typedef pair< int , int > psi;
int prim[ maxn+ 30 ] ;
ll phi[ maxn+ 30 ] ;
int tot;
bool mark[ maxn+ 30 ] ;
ll mod, n, m, p;
ll F[ maxn+ 30 ] , q[ maxn+ 30 ] , s[ maxn+ 30 ] , g[ maxn+ 30 ] ;
map< ll, ll> mp;
ll Pow ( ll a, ll b, ll p) {
ll res = 1 ;
a % = p;
while ( b) {
if ( b & 1 ) res = res * a % p;
a = a * a % p;
b >>= 1 ;
}
return res;
}
void init ( ) {
F[ 1 ] = g[ 1 ] = phi[ 1 ] = 1 ;
for ( ll i = 2 ; i <= maxn; i ++ ) {
if ( ! mark[ i] ) {
prim[ ++ tot] = i;
phi[ i] = i - 1 ;
g[ i] = s[ i] = 2 * i- 1 ;
}
for ( ll j = 1 ; j <= tot; j ++ ) {
if ( i * prim[ j] > maxn) break ;
mark[ i * prim[ j] ] = 1 ;
if ( i % prim[ j] == 0 ) {
s[ i* prim[ j] ] = ( s[ i] + phi[ i] + 0ll ) * prim[ j] ;
phi[ i * prim[ j] ] = phi[ i] * prim[ j] ;
g[ i* prim[ j] ] = g[ i] / s[ i] * s[ i* prim[ j] ] ;
break ;
}
phi[ i * prim[ j] ] = phi[ prim[ j] ] ;
s[ i* prim[ j] ] = s[ prim[ j] ] ;
g[ i* prim[ j] ] = g[ i] * s[ i* prim[ j] ] ;
}
F[ i] = ( F[ i- 1 ] + g[ i] ) % p;
}
}
inline ll GetSum ( ll n) {
return n * ( n+ 1 ) / 2 % p;
}
inline ll GetRes ( ll n) {
ll res = 0 ;
for ( ll l = 1 , r; l <= n; l = r + 1 ) {
r = n / ( n / l) ;
res = ( res + ( GetSum ( r) - GetSum ( l- 1 ) ) * GetSum ( n/ l) % p) % p;
}
return res;
}
inline ll GetS ( ll n) {
if ( n <= maxn) return F[ n] ;
if ( mp[ n] ) return mp[ n] ;
ll res = GetRes ( n) ;
for ( ll l = 2 , r; l <= n; l = r + 1 ) {
r = n / ( n / l) ;
res = ( res - GetS ( n/ l) * ( r- l+ 1 ) % p) % p;
}
res = ( res + p) % p;
return mp[ n] = res;
}
ll solve ( ll n) {
ll res = 0 ;
for ( ll l = 1 , r; l <= n; l = r + 1 ) {
r = n / ( n / l) ;
res = ( res + ( n/ l) * ( n/ l) % p * ( GetS ( r) - GetS ( l- 1 ) ) ) % p;
}
return ( res+ p) % p;
}
int main ( int argc, char * args[ ] ) {
scanf ( "%lld %lld %lld" , & n, & m, & mod) ;
p = mod - 1 ;
init ( ) ;
ll res = solve ( n) ;
printf ( "%lld\n" , Pow ( m, res, mod) ) ;
return 0 ;
}