Description
有一张n×m的数表,其第i行第j列(1<=i<=n,1<=j<=m)的数值为能同时整除i和j的所有自然数之和,给定a,计算数表中不大于a的数之和
Input
输入包含多组数据,输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据
(1<=n,m<=10^5,1<=Q<=2×10^4)
Output
对每组数据,输出一行一个整数,表示答案模2^31的值
Sample Input
2
4 4 3
10 10 5
Sample Output
20
148
Solution
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 111111
typedef long long ll;
bool check[maxn];
int prime[maxn],mu[maxn],ans[maxn];
pair<int,int>f[maxn];
void Moblus(int n)
{
memset(check,0,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2;i<=n;i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0;j<tot;j++)
{
if(i*prime[j]>n)break;
check[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++)f[i].second=i;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i)
f[j].first+=i;
sort(f+1,f+1+n);
}
struct Query
{
int n,m,a,id;
Query(){};
Query(int _n,int _m,int _a,int _id)
{
n=_n,m=_m,a=_a,id=_id;
}
bool operator <(const Query &t)const
{
return a<t.a;
}
}query[maxn];
struct BIT
{
int b[maxn];
#define lowbit(x) (x&(-x))
void init()
{
memset(b,0,sizeof(b));
}
void update(int x,ll v)
{
while(x<maxn)
{
b[x]+=v;
x+=lowbit(x);
}
}
int ask(int x)
{
int ans=0;
while(x>0)
{
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
}bit;
int solve(int n,int m)
{
int ans=0;
for(int i=1,next=0;i<=n;i=next+1)
{
next=min(n/(n/i),m/(m/i));
ans+=(bit.ask(next)-bit.ask(i-1))*(n/i)*(m/i);
}
return ans&0x7fffffff;
}
int main()
{
Moblus(maxn-10);
int T,M=0;
scanf("%d",&T);
for(int i=0;i<T;i++)
{
int n,m,a;
scanf("%d%d%d",&n,&m,&a);
if(n>m)swap(n,m);
M=max(M,n);
query[i]=Query(n,m,a,i);
}
sort(query,query+T);
bit.init();
for(int i=0,res=1;i<T;i++)
{
int cnt=0;
while(f[res].first<=query[i].a&&cnt<M)
{
for(int j=f[res].second,k=1;j<=M;j+=f[res].second,k++)
bit.update(j,f[res].first*mu[k]);
res++;
if(f[res].second<=M)cnt++;
}
ans[query[i].id]=solve(query[i].n,query[i].m);
}
for(int i=0;i<T;i++)printf("%d\n",ans[i]);
return 0;
}