首先不考虑a的限制
设 S(i)为i的约数和
据约数和定理
先将i分解因数
$$ i=p_1^{q_1}p_2^{q_2}...p_k^{q_k}$$
$$S(i)=prod_{i=1}^ksum_{j=0}^{q_i}p_i^j$$
当i与j互质时,S(i*j)=S(i)*S(j),满足积性函数性质,所以可以线性删出来
设g(i)为i最小质因数各幂次的加和
1.当i是质数,g(i)=S(i)=i+1
2.当i不与p(质数)互质是,S(i*p)=S(i)/g(i)*g(i*p)
3.当i与p互质时,S(i*p)=S(i)*(p+1)
(具体可见code)
题目让求$$ans=sum_{i=1 j=1}^{i<=n j<=m}S(gcd(i,j))$$
设f(i)为gcd(x,y)==i的(x,y)数
F(i)为i|gcd(x,y)的(x,y)数
$$ f(i)=sum_{i|d}mu(frac{d}{i})F(d)$$
$$ f(i)=sum_{i|d}mu(frac{d}{i})lfloorfrac{n}{d} floorlfloorfrac{m}{i} floor$$
那么
$$ans=sum_{i=1}^{min(n,m)}S(i)f(i)$$
$$(枚举约数) ans=sum_{i=1}^{min(n,m)}S(i)sum_{i|d}mu(frac{d}{i})lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor$$
$$(枚举d) ans=sum_{d=1}^{min(n,m)}lfloorfrac{n}{d} floorlfloorfrac{m}{d} floorsum_{i|d}S(i)mu(frac{d}{i})$$
然后考虑加上a的限制条件,发现只要离线处理,用树状数组维护后面一项就行了
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=20006;
const int N=100006;
struct VV
{
int v,order;
bool friend operator < (VV a,VV b)
{
return a.v<b.v;
}
}ji[N];
int prime[N],cnt;
bool he[N];
int mu[N],g[N];
void chu()
{
mu[1]=1;g[1]=1;ji[1].v=1;ji[1].order=1;
for(int i=2;i<N;++i)
{
ji[i].order=i;
if(!he[i])
{
prime[++cnt]=i;
mu[i]=-1;
g[i]=i+1;
ji[i].v=i+1;
}
for(int j=1;j<=cnt&&prime[j]*i<N;++j)
{
he[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
g[i*prime[j]]=g[i]*prime[j]+1;
ji[i*prime[j]].v=ji[i].v/g[i]*g[i*prime[j]];
break;
}
mu[i*prime[j]]=-mu[i];
g[i*prime[j]]=prime[j]+1;
ji[i*prime[j]].v=ji[i].v*(prime[j]+1);
}
}
/*printf("
");
for(int i=1;i<=10;++i)
printf("%d ",ji[i].v);
printf("
");*/
sort(ji+1,ji+N);
}
struct Q
{
int n,m,A;
int order;
bool friend operator < (Q a,Q b)
{
return a.A<b.A;
}
}q[M];
int an[M];
int m;
int c[N];
void add(int pos,int val)
{
for(int i=pos;i<N;i+=(i&(-i)) )
c[i]+=val;
}
int qq(int pos)
{
int ans=0;
for(int i=pos;i>0;i-=(i&(-i)) )
ans+=c[i];
return ans;
}
inline void mk(int pos,int val)
{
for(int i=pos;i<N;i+=pos )
{
add(i,val*mu[i/pos]);
}//cout<<1;
}
int get(int n,int m)
{
if(n>m)
swap(n,m);
int nx;
int ans=0;
for(int i=1;i<=n;)
{
nx=min( n/(n/i),m/(m/i) );
ans+=(n/i)*(m/i)*( qq(nx)-qq(i-1) );
i=nx+1;
}
return ans;
}
void work()
{
int IINF=(1<<31)-1,now=1;
for(int i=1;i<=m;++i)
{
while(ji[now].v<=q[i].A)
mk(ji[now].order,ji[now].v),++now;
an[q[i].order]=get(q[i].n,q[i].m)&IINF;
}
}
int main(){
//freopen("in.in","r",stdin);
freopen("sdoi2014shb.in","r",stdin);
freopen("sdoi2014shb.out","w",stdout);
//freopen("out.out","w",stdout);
chu();
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
q[i].order=i;
scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].A);
}
sort(q+1,q+1+m);
work();
for(int i=1;i<=m;++i)
printf("%d
",an[i] );
}