题目
解法:莫比乌斯反演
一道较简单的莫比乌斯反演,推推式子就OK了。
单次询问时间复杂度: O(π(n)min(n,m)−−−−−−−−√) O ( π ( n ) min ( n , m ) ) ,一眼看过去,诶,能过,突然就看到了多组数据 T⩽105 T ⩽ 10 5 。。凉了呀
发现式中有迭代变量的乘积,于是设 t=dp t = d p ,就有:
在筛出素数后,迭代求出
∑pμ(tp)
∑
p
μ
(
t
p
)
的前缀和,
即可使用分块求解。
时间复杂度: O(T⋅(π(n)logπ(n)+n−−√)) O ( T ⋅ ( π ( n ) log π ( n ) + n ) )
AC代码
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=10000000;
vector<int> prime;
bool check[10000001];
int T,n,m;
long long summu[10000001],mu[10000001];
void sieve(){
mu[1]=1ll;
for(int i=2;i<=N;++i){
if(!check[i])prime.push_back(i),mu[i]=-1ll;
for(int j:prime){
if(i*j>N)break;
mu[i*j]=-mu[i],check[i*j]=true;
if(i%j==0){mu[i*j]=0;break;}
}
}
for(int i:prime)for(int j=1;i*j<=N;++j)summu[i*j]+=mu[j];
for(int i=1;i<=N;++i)summu[i]+=summu[i-1];
}
void solve(int n,int m){
if(n>m)swap(n,m);
int lst;long long res=0ll;
for(int i=1;i<=n;i=lst+1)lst=min(n/(n/i),m/(m/i)),res+=(summu[lst]-summu[i-1])*(n/i)*(m/i);
printf("%lld\n",res);
}
int main(){
sieve();
scanf("%d",&T);for(int i=1;i<=T;++i)scanf("%d%d",&n,&m),solve(n,m);
}