题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3529
题意:有一张n×m的数表,其第i行第j列的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。
思路:首先求出每个数字的约数之和,(i,sumFactor[i]),将这些二元组升序排序,将所有sumFactor小于等于a的插入树状数组,插入时,add(j*i,mou[j]*sumFactor[i]).
struct node
{
int n,m,id;
i64 a;
};
node a[N];
pair<i64,int> b[N];
int n,m;
i64 sum[N];
int cmp(node a,node b)
{
return a.a<b.a;
}
i64 ans[N],S[N];
void add(int x,i64 y)
{
while(x<N) S[x]+=y,x+=x&-x;
}
i64 get(int x)
{
i64 ans=0;
while(x) ans+=S[x],x-=x&-x;
return ans;
}
int id;
void Add(i64 x)
{
while(id+1<N&&b[id+1].first<=x)
{
id++;
int j;
for(j=1;j*b[id].second<N;j++)
{
add(j*b[id].second,b[id].first*mou[j]);
}
}
}
void cal(int t)
{
int n=a[t].n;
int m=a[t].m;
int L,R;
for(L=1;L<=n&&L<=m;L=R+1)
{
R=min(n/(n/L),m/(m/L));
ans[a[t].id]+=(get(R)-get(L-1))*(n/L)*(m/L);
}
}
int main()
{
initMou();
int i,j;
for(i=1;i<N;i++)
{
for(j=i;j<N;j+=i) sum[j]+=i;
}
for(i=1;i<N;i++) b[i]=MP(sum[i],i);
sort(b+1,b+N);
RD(n);
FOR1(i,n) RD(a[i].n,a[i].m),RD(a[i].a),a[i].id=i;
sort(a+1,a+n+1,cmp);
for(i=1;i<=n;i++)
{
Add(a[i].a);
cal(i);
}
for(i=1;i<=n;i++) printf("%d\n",ans[i]&0x7fffffff);
}