题目链接:https://ac.nowcoder.com/acm/contest/549/J
参考题解:https://www.cnblogs.com/henry-1202/p/10699252.html#_label7
反演后迪利克雷卷积,然后线性筛卷积,再分块处理。
预处理复杂度O(N) ,每次询问O(sqrt(N))。
并没有使用杜教筛继续优化。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+100;
const int mod = 1e9+7;
int prime[N]; //素数表下标从1开始
bool mark[N]; //mark[i]==1表示i不是素数
ll F[N]; //要筛的积性函数
int tot;
int Low[N]; // Low[i]表示i的最小质因子的指数次幂,i=p1^a1+p2^a2+p3^a3.....,low[i]=p1^a1;
void get_list(int n){
mark[1] = 1;
F[1] = 1;
Low[1] = 1; //给出F[1]的值
for(int i = 2;i <= n;i ++){
if(!mark[i]) {
Low[i] = i;
prime[++tot] = i;
F[i] = (1ll*i*i-1)%mod; //给出F[p]的值,p表示质数
}
for(int j = 1;j<=tot&&prime[j]*i<=n;j ++){ //prime[j]永远是被筛数的最小质因子,且一定小于等于i的最小质因子
mark[i*prime[j]] = 1;
if(!(i%prime[j])) { //i和prime[j]不互质的情况
Low[i*prime[j]] = Low[i]*prime[j];
if(Low[i]==i) F[i*prime[j]] = F[i]*prime[j]%mod*prime[j]%mod; //i中只包含prime[j]这一个质因子,此时给出F[p^x]的值
else F[i*prime[j]] = F[i/Low[i]]*F[Low[i]*prime[j]]%mod; //i中还包含其他质因子
break;
}
Low[i*prime[j]] = prime[j]; //i和prime[j]互质的情况
F[i*prime[j]] = F[i]*F[prime[j]]%mod;
}
}
for(int i = 1; i <= n; i++) F[i] = (F[i-1]+F[i])%mod;
}
int main() {
get_list(1e6);
ll n,m;
cin>>n>>m;
if(n>m) swap(n,m);
ll ans = 0;
for(ll l=1,r;l<=n;l=r+1) {
r=min(n/(n/l),m/(m/l));
ans = (ans + (n/l)*(m/l)%mod*(F[r]-F[l-1]+mod)%mod)%mod;
}
cout<<ans;
return 0;
}