P4240 毒瘤之神的考验

经过一番推导可得:

\[\sum_{T=1}^{\min(n,m)} \left ( \sum_{d|T} \frac{d}{\varphi(d)}\mu(\frac{T}{d}) \right) \sum_{i=1}^{\lfloor \frac{n}{T} \rfloor}\varphi(iT) \sum_{j=1}^{\lfloor \frac{m}{T} \rfloor} \varphi(jT) \]

\(\displaystyle f(n)=\sum_{d|T} \frac{d}{\varphi(d)} \mu(\frac{T}{d})\) ,可以 \(\mathcal O(n \ln n)\) 预处理

\(\displaystyle G(n,T)=\sum_{i=1}^{n} \varphi(iT)\) , \(G(n,T)\) 的状态数为 \(n \ln n\) , 同样可以 \(\mathcal O(n \ln n)\) 递推

\[\sum_{T=1}^{\min(n,m)} f(T)G(\lfloor \frac{n}{T} \rfloor,T)G(\lfloor \frac{m}{T} \rfloor,T) \]

\(\displaystyle S(n,x,y)=\sum_{T=1}^n f(T) G(x,T)G(y,T)\) , 那么有:

\[S(n,x,y)=S(n-1,x,y)+f(n)G(x,n)G(y,n) \]

对于 \(T \le \frac{N}{B}\) 的部分直接算,对于 \(T > \frac{N}{B}\) 的部分整除分块并通过 \(S\) 算。

\(S\) 的复杂度的分析:

首先 \(n \le N\)\(x,y \le B\) , 上界为 \(nB^2\)

注意到使 \(S(n,x,y)\) 不同于 \(S(n-1,x,y)\) 的条件为 \(G(x,n) G(y,n) \not=0\) , 即 \(n \le \frac{N}{\max(x,y)}\)

那么计算 \(S\) 的复杂度即为 \(\displaystyle \sum_{i=1}^B\sum_{j=1}^B \frac{N}{\max(i,j)}=O(NB)\)

\(B\)\(\sqrt n\) 可得最优复杂度。

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;

const int MAXN = 1e5 , MAXB = 150 , Mod = 998244353 , Inf = 0x3f3f3f3f;
inline int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
inline int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; } 
inline int Mul( int x , int y ) { return 1ll * x * y % Mod; }
int Qkpow( int x , int po ) { int p = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) p = Mul( p , x ); return p; }
int Inv( int x ) { return Qkpow( x , Mod - 2 ); }

int prnum , prime[ MAXN / 10 + 5 ] , phi[ MAXN + 5 ] , mu[ MAXN + 5 ] , f[ MAXN + 5 ];
bool vis[ MAXN + 5 ];
void sieve( ) {
	phi[ 1 ] = 1 , mu[ 1 ] = 1;
	for( int i = 2 ; i <= MAXN ; i ++ ) {
		if( !vis[ i ] ) {
			prime[ ++ prnum ] = i;
			phi[ i ] = i - 1 , mu[ i ] = Mod - 1;
		}
		for( int j = 1 ; j <= prnum && 1ll * i * prime[ j ] <= MAXN ; j ++ ) {
			vis[ i * prime[ j ] ] = 1;
			if( i % prime[ j ] == 0 ) {
				phi[ i * prime[ j ] ] = phi[ i ] * prime[ j ];
				break;
			}
			phi[ i * prime[ j ] ] = phi[ i ] * ( prime[ j ] - 1 );
			mu[ i * prime[ j ] ] = Mod - mu[ i ];
		}
	}
	for( int i = 1 ; i <= MAXN ; i ++ )
		for( int j = i ; j <= MAXN ; j += i )
			f[ j ] = Add( f[ j ] , Mul( Mul( i , Inv( phi[ i ] ) ) , mu[ j / i ] ) );
}

int T , n , m , B = 100;
vector< int > G[ MAXN + 5 ] , S[ MAXB + 5 ][ MAXB + 5 ];
int main( ) {
	sieve();
	
	for( int i = 1 ; i <= MAXN ; i ++ ) G[ i ].resize( MAXN / i + 1 );
	for( int i = 1 ; i <= MAXN ; i ++ ) {
		G[ 1 ][ i ] = phi[ i ];
		for( int j = 2 ; 1ll * i * j <= MAXN ; j ++ ) G[ j ][ i ] = Add( G[ j - 1 ][ i ] , phi[ j * i ] );
	}
	for( int i = 1 ; i <= B ; i ++ )
		for( int j = 1 ; j <= B ; j ++ ) {
			S[ i ][ j ].resize( MAXN / max( i , j ) + 1 );
			for( int k = 1 ; k <= MAXN / max( i , j ) ; k ++ )
				S[ i ][ j ][ k ] = Add( S[ i ][ j ][ k - 1 ] , Mul( Mul( G[ i ][ k ] , G[ j ][ k ] ) , f[ k ] ) );
		}
	
	scanf("%d",&T);
	while( T -- ) {
		scanf("%d %d",&n,&m);
		int Ans = 0 , d = min( n , m );
		for( int i = 1 ; i <= min( MAXN / B , d ) ; i ++ ) Ans = Add( Ans , Mul( f[ i ] , Mul( G[ n / i ][ i ] , G[ m / i ][ i ] ) ) );
		for( int l = MAXN / B + 1 , r ; l <= d ; l = r + 1 ) {
			r = min( n / ( n / l ) , m / ( m / l ) );
			Ans = Add( Ans , Sub( S[ n / l ][ m / l ][ r ] , S[ n / l ][ m / l ][ l - 1 ] ) );
		}
		printf("%d\n", Ans );
	}
	return 0;
}
posted @ 2021-12-21 16:16  chihik  阅读(22)  评论(0编辑  收藏  举报