题目
解法:莫比乌斯反演
一道较简单的莫比乌斯反演,推推式子就OK了。
单次询问时间复杂度: ,一眼看过去,诶,能过,突然就看到了多组数据 。。凉了呀
发现式中有迭代变量的乘积,于是设 ,就有:
在筛出素数后,迭代求出
的前缀和,
即可使用分块求解。
时间复杂度:
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(){
scanf("%d",&T);
sieve();
for(int i=1;i<=T;++i){
scanf("%d%d",&n,&m);
solve(n,m);
}
}