收获:
当一个东西的取值有限时,我们可以枚举它,然后统计它被计算了多少次。
#include <cstdio>
#include <iostream>
using namespace std; typedef long long dnt; int prm[], isnot[], mu[], f[], ptot; void init( int n ) {
mu[] = ;
for( int i=; i<=n; i++ ) {
if( !isnot[i] ) {
prm[++ptot] = i;
mu[i] = -;
}
for( int j=; j<=ptot && i*prm[j]<=n; j++ ) {
isnot[i*prm[j]]=true;
if( i%prm[j]== ) {
mu[i*prm[j]] = ;
break;
}
mu[i*prm[j]] = -mu[i];
}
}
for( int i=; i<=ptot; i++ ) {
int p = prm[i];
for( int j=p; j<=n; j+=p )
f[j] += mu[j/p];
}
for( int i=; i<=n; i++ )
f[i] += f[i-];
}
dnt calc( dnt n, dnt m ) {
if( n>m ) swap(n,m);
dnt rt = ;
for( int i=; i<=n; i++ ) {
int ii = min( n/(n/i), m/(m/i) );
rt += (f[ii]-f[i-])*(n/i)*(m/i);
i = ii;
}
return rt;
}
int main() {
int T;
init( );
scanf( "%d", &T );
while( T-- ) {
int n, m;
scanf( "%d%d", &n, &m );
printf( "%lld\n", calc(n,m) );
}
}