P4619 [SDOI2018]旧试题
\[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^Cd(ijk)
\]
\[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sum_{x|i}\sum_{y|j}\sum_{z|k}[(x,y)=1][(y,z)=1][(x,z)=1]
\]
\[\sum_{x=1}^A\sum_{y=1}^B\sum_{z=1}^C \lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor [(x,y)=1][(y,z)=1][(x,z)=1]
\]
\[\sum_{x=1}^A\sum_{y=1}^B\sum_{z=1}^C \lfloor \frac{A}{x} \rfloor \lfloor \frac{B}{y} \rfloor \lfloor \frac{C}{z} \rfloor \sum_{d_1|(x,y)}\mu(d_1)\sum_{d_2|(y,z)}\mu(d_2)\sum_{d_3|(x,z)}\mu(d_3)
\]
\[\sum_{d_1=1}^{min(A,B)}\sum_{d_2=1}^{min(B,C)}\sum_{d_3=1}^{min(A,C)} \mu(d_1)\mu(d_2)\mu(d_3) \sum_{[d_1,d_3]|x} \lfloor \frac{A}{x} \rfloor \sum_{[d_1,d_2)]|y} \lfloor \frac{B}{y} \rfloor \sum_{[d_2,d_3]|z} \lfloor \frac{C}{z} \rfloor
\]
令 \(f(n,A)=\sum_{n|d} \lfloor \frac{A}{d} \rfloor\) , 可以 \(\Theta(n \ln n)\) 预处理 \(f(n,A/B/C)\)
\[\sum_{d_1=1}^{min(A,B)}\sum_{d_2=1}^{min(B,C)}\sum_{d_3=1}^{min(A,C)} \mu(d_1)\mu(d_2)\mu(d_3) f([d_1,d_3],A) f([d_1,d_2],B) f([d_2,d_3],C)
\]
注意到当 \([d_1,d_3]>A~,~[d_1,d_2]>B~,~[d_2,d_3]>C\) 时函数值为0 , \(\mu\) 的大部分值为 \(0\),所以有贡献的情况不多。
对于 \((u,v)\),当 \(\mu(u)\not=0, \mu(v)\not=0\) 且 \([u,v] \le \max \{A,B,C\}\) 时连边。
\(u,v\) 可以枚举最大公因数 \(d\) 后枚举倍数 \(i,j\) , 但要保证 \((i,j)=1\)。
这样图上的三元环便对应着每一种有贡献的情况。
最后特殊统计一下三个点相等和两个点相等的情况。
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
const int Mod = 1e9 + 7 , MAXN = 1e5;
int t , A , B , C , n , m;
int cnt , vt[ MAXN + 5 ] , Deg[ MAXN + 5 ];
struct node {
int u , v , w;
}E[ 8 * MAXN + 5 ];
struct Edge {
int v , w;
};
vector< Edge > Graph[ MAXN + 5 ];
int k , prime[ MAXN + 5 ] , mu[ MAXN + 5 ] , f[ 3 ][ MAXN + 5 ];
bool vis[ MAXN + 5 ];
void Init( ) {
mu[ 1 ] = 1;
for( int i = 2 ; i <= n ; i ++ ) {
if( !vis[ i ] ) {
prime[ ++ k ] = i;
mu[ i ] = -1;
}
for( int j = 1 ; j <= k && 1ll * i * prime[ j ] <= MAXN ; j ++ ) {
vis[ i * prime[ j ] ] = 1;
if( i % prime[ j ] == 0 ) break;
mu[ i * prime[ j ] ] = -mu[ i ];
}
}
for( int i = 1 ; i <= n ; i ++ ) {
f[ 0 ][ i ] = f[ 1 ][ i ] = f[ 2 ][ i ] = 0;
for( int j = i ; j <= n ; j += i ) {
f[ 0 ][ i ] = ( f[ 0 ][ i ] + A / j ) % Mod;
f[ 1 ][ i ] = ( f[ 1 ][ i ] + B / j ) % Mod;
f[ 2 ][ i ] = ( f[ 2 ][ i ] + C / j ) % Mod;
}
}
}
int chk( long long x ) {
return ( x % Mod + Mod ) % Mod;
}
int Calc( int u , int v , int w ) {
return chk( 1ll * f[ 0 ][ u ] * f[ 1 ][ v ] % Mod * f[ 2 ][ w ] % Mod );
}
int Gcd( int a , int b ) {
return !b ? a : Gcd( b , a % b );
}
int Solve( ) {
int Ans = 0;
for( int i = 1 ; i <= m ; i ++ )
Ans = ( Ans + chk( mu[ i ] * mu[ i ] * mu[ i ] * Calc( i , i , i ) ) ) % Mod;
cnt = 0;
for( int i = 1 ; i <= n ; i ++ ) Deg[ i ] = 0;
for( int d = 1 ; d <= n ; d ++ )
for( int i = 1 ; i <= n / d ; i ++ )
for( int j = i + 1 ; j <= n / i / d ; j ++ ) {
int u = i * d , v = j * d , l = i * j * d;
if( Gcd( i , j ) != 1 || !mu[ u ] || !mu[ v ] ) continue;
Ans = ( Ans + chk( mu[ u ] * mu[ u ] * mu[ v ] * chk( 1ll * Calc( u , l , l ) + Calc( l , u , l ) + Calc( l , l , u ) ) ) ) % Mod;
Ans = ( Ans + chk( mu[ u ] * mu[ v ] * mu[ v ] * chk( 1ll * Calc( v , l , l ) + Calc( l , v , l ) + Calc( l , l , v ) ) ) ) % Mod;
E[ ++ cnt ] = { u , v , l };
}
for( int i = 1 ; i <= n ; i ++ ) Graph[ i ].clear( );
for( int i = cnt , u , v , w ; i >= 1 ; i -- ) {
u = E[ i ].u , v = E[ i ].v , w = E[ i ].w;
if( Deg[ u ] < Deg[ v ] || ( Deg[ u ] == Deg[ v ] && u < v ) )
Graph[ u ].push_back( { v , w } );
else
Graph[ v ].push_back( { u , w } );
}
for( int u = 0 ; u <= n ; u ++ ) {
if( !mu[ u ] ) continue;
for( int i = 0 ; i < Graph[ u ].size( ) ; i ++ ) vt[ Graph[ u ][ i ].v ] = Graph[ u ][ i ].w;
for( int i = 0 ; i < Graph[ u ].size( ) ; i ++ ) {
int v = Graph[ u ][ i ].v , uw = Graph[ u ][ i ].w;
if( !mu[ v ] ) continue;
for( int j = 0 ; j < Graph[ v ].size( ) ; j ++ ) {
int w = Graph[ v ][ j ].v , vw = Graph[ v ][ j ].w;
if( !mu[ w ] ) continue;
if( vt[ w ] ) {
int ww = vt[ w ];
Ans = ( Ans + chk( mu[ u ] * mu[ v ] * mu[ w ] * chk( 1ll * Calc( uw , vw , ww ) + Calc( uw , ww , vw ) + Calc( vw , uw , ww ) + Calc( vw , ww , uw ) + Calc( ww , uw , vw ) + Calc( ww , vw , uw ) ) ) ) % Mod;
}
}
}
for( int i = 0 ; i < Graph[ u ].size( ) ; i ++ ) vt[ Graph[ u ][ i ].v ] = 0;
}
return Ans;
}
int main( ) {
scanf("%d", &t );
while( t -- ) {
scanf("%d %d %d", &A , &B , &C );
n = max( A , max( B , C ) );
m = min( A , min( B , C ) );
Init( );
printf("%d\n", Solve( ) );
}
return 0;
}