P3312 [SDOI2014]数表

\[\sum_{i=1}^n\sum_{j=1}^m \sigma((i,j)) \]

\[\sum_{d=1}^{\min(n,m)}\sigma(d)\sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=d] \]

\[\sum_{d=1}^{\min(n,m)}\sigma(d)\sum_{t=1}^{\frac{\min(n,m)}{d}}\mu(t) \lfloor \frac{n}{dt}\rfloor \lfloor \frac{m}{dt} \rfloor \]

\[\sum_{T=1}^{\min(n,m)}\lfloor \frac{n}{T}\rfloor \lfloor \frac{m}{T}\rfloor \sum_{d|T}\sigma(d)\mu(\frac{T}{d}) \]

如果没有 \(a\) 的限制 ,\(\sigma\)\(\mu\) 的卷积为 \(id\)

加入 \(a\) 的限制后,只要满足 \(\sigma (d) \le a\) 即可。

那么将询问对 \(a\) 从小到大排序,通过枚举倍数加入 \(\sigma(d)\mu(\frac{T}{d})\) 的贡献。

\(f(n)=\sum_{d|n} \sigma(d)\mu(\frac{T}{d})\)

我们需要单点修改 \(f(n)\) , 以及在数论分块时区间查询,可以用树状数组维护。

时间复杂度 \(\Theta(n \log^2 n+q\sqrt n \log n)\)

#include <cstdio> 
#include <iostream>
#include <algorithm>
using namespace std;
#define uint unsigned int
#define Pair pair< int , int > 
#define fir first
#define sec second

const int MAXN = 1e5 , MAXQ = 2e4;

struct BIT {
	#define Lowbit( x ) ( x & -x )
	
	uint Arr[ MAXN + 5 ];
	void Update( int x , int val ) { 
		for( ; x <= MAXN ; x += Lowbit( x ) ) Arr[ x ] += val; 
	}
	uint Sum( int l , int r ) { 
		uint Ans = 0; l --;
		for( ; l ; l -= Lowbit( l ) ) Ans -= Arr[ l ]; 
		for( ; r ; r -= Lowbit( r ) ) Ans += Arr[ r ]; 
		return Ans; 
	} 
}Tree;

int prn , prime[ MAXN + 5 ] , mu[ MAXN + 5 ] , sigma[ MAXN + 5 ];
Pair f[ MAXN + 5 ];
bool vis[ MAXN + 5 ];
void sieve( ) {
	mu[ 1 ] = 1; sigma[ 1 ] = 1;
	for( int i = 2 ; i <= MAXN ; i ++ ) {
		if( !vis[ i ] ) { 
			prime[ ++ prn ] = i; 
			mu[ i ] = -1 , sigma[ i ] = i + 1;
		}
		for( int j = 1 ; j <= prn && 1ll * i * prime[ j ] <= MAXN ; j ++ ) {
			vis[ i * prime[ j ] ] = 1;
			if( i % prime[ j ] == 0 ) {
				sigma[ i * prime[ j ] ] = ( prime[ j ] + 1 ) * sigma[ i ] - prime[ j ] * sigma[ i / prime[ j ] ];
				break;
			}
			mu[ i * prime[ j ] ] = -mu[ i ];
			sigma[ i * prime[ j ] ] = sigma[ i ] * sigma[ prime[ j ] ]; 
		}
	}
	for( int i = 1 ; i <= MAXN ; i ++ ) f[ i ] = make_pair( sigma[ i ] , i );
	sort( f + 1 , f + MAXN + 1 );
}

int t; uint Ans[ MAXN + 5 ];
struct Query {
	int n , m , a , id;
	bool operator < ( const Query &oth ) const {
		return a < oth.a;
	}	
}Q[ MAXQ + 5 ];

int main( ) {
	sieve( );
	scanf("%d",&t);
	for( int i = 1 ; i <= t ; i ++ )
		scanf("%d %d %d",&Q[ i ].n,&Q[ i ].m,&Q[ i ].a) , Q[ i ].id = i; 
	sort( Q + 1 , Q + t + 1 );
	
	for( int i = 1 , d = 0 ; i <= t ; i ++ ) {
		for( ; d + 1 <= MAXN && f[ d + 1 ].fir <= Q[ i ].a ; d ++ )
			for( int j = f[ d + 1 ].sec ; j <= MAXN ; j += f[ d + 1 ].sec )
				Tree.Update( j , f[ d + 1 ].fir * mu[ j / f[ d + 1 ].sec ] );
		
		int n = Q[ i ].n , m = Q[ i ].m;
		for( int l = 1 , r ; l <= min( n , m ) ; l = r + 1 ) {
			r = min( n / ( n / l ) , m / ( m / l ) );
			Ans[ Q[ i ].id ] += 1u * ( n / l ) * ( m / l ) * Tree.Sum( l , r );
		}
	}
	for( int i = 1 ; i <= t ; i ++ ) printf("%d\n", Ans[ i ] & 2147483647 );
	return 0;
}
posted @ 2021-04-08 20:29  chihik  阅读(38)  评论(0编辑  收藏  举报