题解 P3455 【[POI2007]ZAP-Queries】
求
先上套路
我们要求的就是
把后面的提出来
前面分块后面前缀和就好了
但是很快就发现不对了,后面那个东西根本没法前缀和,因为每一次的
但是别忘了
如果
所以我们要求
可以直接求
就好了
这样这些互质的数对乘上
所以就相当于上面的柿子里
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 50005
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
int p[maxn>>1],mu[maxn],f[maxn];
LL pre[maxn];
int n,m,d,t,T;
int main()
{
f[1]=1,mu[1]=1;
for(re int i=2;i<=50000;i++)
{
if(!f[i]) p[++p[0]]=i,mu[i]=-1;
for(re int j=1;j<=p[0]&&p[j]*i<=50000;j++)
{
f[p[j]*i]=1;
if(i%p[j]==0) break;
mu[p[j]*i]=-1*mu[i];
}
}
for(re int i=1;i<=50000;i++) pre[i]+=pre[i-1]+mu[i];
T=read();
while(T--)
{
n=read(),m=read(),t=read();
if(n>m) std::swap(n,m);
n/=t,m/=t;
LL ans=0;
for(re int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(LL)(n/l)*(m/l)*(pre[r]-pre[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}