版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89788385
欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
先%一波dalao——PoPoQQQ
话说这道题真的毒瘤啊!
一句话题意,设 为 的约数和,求
假设现在先无 这个限制条件。
由Zap(务必看一看)可知,
可以转化为
,我们设
表示满足
并且
的二元组有多少对,显然
令
,有
所以
预先处理一下, 数组。
所以没有限制条件 下的答案,就如上所求。
我们只要排序一下 就行了。
那么有限制条件 时,我们要多开一个树状数组,并将 排序。
每次询问时,进行相应操作即可。
AC code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define gc getchar()
using namespace std;
const int M=4e4+10;
const int N=1e5+10;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int Q,mx,m;
struct data{int n,m,a,id;}q[M];int ans[M];
bool v[N];int prime[N],mu[N],c[N];
bool cmp1(data a,data b){return a.a<b.a;}
struct node{int sum,id;}f[N];
bool cmp2(node a,node b){return a.sum<b.sum;}
void add(int x,int y){for(;x<=mx;x+=x&-x)c[x]+=y;}
int ask(int x)
{
int tmp=0;
for(;x;x-=x&-x)tmp+=c[x];
return tmp;
}
void pre()
{
mu[1]=1;m=0;
for(int i=2;i<=mx;i++)
{
if(!v[i])prime[++m]=i,mu[i]=-1;
for(int j=1;j<=m&&prime[j]*i<=mx;j++)
{
v[i*prime[j]]=1;
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].sum+=i;
for(int i=1;i<=mx;i++)f[i].id=i;
}
void solve(int i)
{
int id=q[i].id,n=q[i].n,m=q[i].m;
for(int x=1,gx;x<=n;x=gx+1)
{
gx=min(n/(n/x),m/(m/x));
ans[id]+=(ask(gx)-ask(x-1))*(n/x)*(m/x);
}
}
int main()
{
qr(Q);
for(int i=1;i<=Q;i++)
{
qr(q[i].n),qr(q[i].m),qr(q[i].a),q[i].id=i;
if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
mx=max(mx,q[i].n);
}
pre();
sort(q+1,q+Q+1,cmp1);
sort(f+1,f+mx+1,cmp2);
int now=0;
for(int i=1;i<=Q;i++)
{
while(now+1<=mx&&f[now+1].sum<=q[i].a)
{
now++;
for(int j=f[now].id;j<=mx;j+=f[now].id)
add(j,f[now].sum*mu[j/f[now].id]);
}
solve(i);
}
for(int i=1;i<=Q;i++)
qw(ans[i]&0x7fffffff),puts("");
return 0;
}