如果不考虑a的限制,这道题就简化了一下。
令
f(x)
表示x的约数和,
g(x)=∑ni=1∑mj=1[gcd(i,j)==x]
那么,
ans=∑ni=1f(i)g(i)
,由某道题可得
g(i)
的表达式。
YY的GCD
g(i)=∑i|dμ(di)[nd][md]
然后,这个问题就大概解决了。
那么如果有限制的话,我们可以先离线,然后用树状数组处理前缀和就好了。
#include<bits/stdc++.h>
#define N 100000
using namespace std;
int T,mx,ans[N+5],lst,n,m;
int prime[N+5],mu[N+5],notp[N+5],cnt;
int c[N+5];
struct question{
int n,m,id,a;
bool operator < (const question &A)const{
return a<A.a;
}
}A[N+5];
pair <int,int>F[N+5];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,b=1;
char c=nc();
for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
return x*b;
}
inline void add(int x,int val)
{
for(;x<=N;x+=x&-x)c[x]+=val;
}
inline int query(int x)
{
int ans=0;
for(;x>=1;x-=x&-x)ans+=c[x];
return ans;
}
inline void init()
{
notp[1]=true;mu[1]=1;
for(int i=2;i<=mx;i++)
{
if(!notp[i])prime[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<=mx;j++)
{
notp[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=mx;i++)
for(int j=i;j<=mx;j+=i)
F[j].first+=i;
for(int i=1;i<=mx;i++)F[i].second=i;
}
int main()
{
freopen("in.txt","r",stdin);
T=read();
for(int i=1;i<=T;i++)A[i].n=read(),A[i].m=read(),A[i].a=read(),A[i].id=i;
for(int i=1;i<=T;i++)if(A[i].n>A[i].m)swap(A[i].n,A[i].m);
for(int i=1;i<=T;i++)mx=max(mx,A[i].m);
sort(A+1,A+T+1);
init();sort(F+1,F+mx+1);
int now=0;
for(int i=1;i<=T;i++)
{
while(now+1<=mx&&F[now+1].first<=A[i].a)
{
now++;
for(int j=F[now].second;j<=mx;j+=F[now].second)
add(j,F[now].first*mu[j/F[now].second]);
}
n=A[i].n,m=A[i].m;
for(int j=1;j<=n;j=lst+1)
{
lst=min(n/(n/j),m/(m/j));
ans[A[i].id]+=(n/j)*(m/j)*(query(lst)-query(j-1));
}
}
for(int i=1;i<=T;i++)printf("%d\n",ans[i]&0x7fffffff);
return 0;
}