題意:
給你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 ;
}