要求的是约数和
如果没有a的限制,直接反演就完了
有a的限制的话,把询问按a排序,用树状数组维护约数和乘上
μ
\mu
μ的前缀和即可
Code:
#include<bits/stdc++.h>
#define mod 2147483648
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e5+5;
struct Q{int n,m,a,id;}q[N];
inline bool cmp1(Q x,Q y){return x.a<y.a;}
int mx;
namespace bit{
int tr[N];
inline int lb(int x){return x&-x;}
inline void add(int x,int y){for(int i=x;i<=mx;i+=lb(i)) tr[i]+=y;}
inline int query(int x){
int res=0;
for(int i=x;i;i-=lb(i)) res+=tr[i];
return res;
}
inline int ask(int l,int r){return query(r)-query(l-1);}
}
using namespace bit;
int pri[N],cnt,mu[N],pt[N];
struct S{int num,sum;}s[N];
inline bool cmp2(S x,S y){return x.sum<y.sum;}
inline void init(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!pt[i]) pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt && i*pri[j]<=n;j++){
pt[i*pri[j]]=1;
if(i%pri[j]==0) break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++){
s[i].num=i;
for(int j=i;j<=n;j+=i) s[j].sum+=i;
}
}
ll ans[N];
inline void solve(int id){
for(int i=1,j;i<=q[id].n;i=j+1){
j=min(q[id].n/(q[id].n/i),q[id].m/(q[id].m/i));
ans[q[id].id]+=(q[id].n/i)*(q[id].m/i)*ask(i,j);
}
}
int main(){
int t=read();
for(int i=1;i<=t;i++){
q[i].n=read(),q[i].m=read(),q[i].a=read();
if(q[i].n>q[i].m) swap(q[i].n,q[i].m);
mx=max(mx,q[i].n);q[i].id=i;
}
init(mx);
sort(q+1,q+t+1,cmp1);
sort(s+1,s+mx+1,cmp2);
int p=0;
for(int i=1;i<=t;i++){
while(p<mx && s[p+1].sum<=q[i].a){
++p;
for(int j=s[p].num;j<=mx;j+=s[p].num) add(j,s[p].sum*mu[j/s[p].num]);
}
solve(i);
}
for(int i=1;i<=t;i++) cout<<ans[i]%mod<<"\n";
return 0;
}