題意:1<=x<=n,1<=y<=m,使得gcd(x,y)=k,k的素因數個數小於等於p
例:24=2*2*2*3,k=4
解:設f[n]爲gcd(a,b)=n的對數
F[d]爲d|gcd(a,b)的對數
f[n]=sigema(mu[i],F[i*n]):
f[1]=mu[1]*F[1]+mu[2]*F[1*2]+...+mu[n]*F[1*n]
f[2]=mu[2]*F[2]+mu[2]*F[2*2]+...+mu[n]*F[2*n]
......
sum=f[1]+f[2]+...+f[n]=G[1]*F[1]+G[2]*F[2]+...+G[n]*F[n]
枚舉每一個i,則i的倍數j爲G[j]提供了mu[j/i]的貢獻,即G[j]+=mu[j/i]
因爲所求爲k的素因數個數,所以將G[j]開成二維數組G[j][p]表示j對素因數個數爲p的貢獻
需要使用分塊加速的方法,否則還是要爆炸
#include <stdio.h>
#include <string.h>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)<(b)?(b):(a))
#define ll __int64
const int maxn=500005;
int num[maxn];
int prime[maxn];
int mu[maxn];
int factor[maxn];
int mbs[maxn][20];
void mobius()
{
memset(num,0,sizeof(num));
int all=0;
mu[1]=1;
factor[1]=0;
for(int i=2;i<maxn;i++)
{
if(!num[i])
{
prime[all++]=i;
mu[i]=-1;
factor[i]=1; //記錄素因數個數
}
for(int j=0;j<all&&i*prime[j]<maxn;j++)
{
num[i*prime[j]]=1;
factor[i*prime[j]]=factor[i]+1;
if(i%prime[j])
{
mu[i*prime[j]]=-mu[i];
}
else
{
mu[i*prime[j]]=0;
break;
}
}
}
return ;
}
void inti()
{
memset(mbs,0,sizeof(mbs));
for(int i=1;i<maxn;i++)
for(int j=i;j<maxn;j+=i)
mbs[j][factor[i]]+=mu[j/i]; //每個j在factor[i]個素因數中的貢獻
/*下面是爲了分塊加速求和*/
for(int i=1;i<maxn;i++)
for(int j=0;j<19;j++)
mbs[i][j]+=mbs[i-1][j];
for(int i=0;i<maxn;i++)
for(int j=1;j<19;j++)
mbs[i][j]+=mbs[i][j-1];
return ;
}
int main()
{
int t,n,m,p;
mobius();
inti();
ll sum;
while(scanf("%d",&t)!=-1)
{
while(t--)
{
scanf("%d%d%d",&n,&m,&p);
if(p>=19) //因爲2^19>500000,所以超過了19就是全體均滿足要求
{
printf("%I64d\n",(ll)n*m);
continue;
}
if(n>m)
{
int te=n;
n=m;
m=te;
}
sum=0;
for(int i=1,last;i<n;i=last+1)
{
last=MIN(n/(n/i),m/(m/i));
//分塊加速,因爲[n/i][m/i]在i遞加過程中具有重複部分,跳掉這些i可是簡化計算,是複雜度降低至sqrt(n)
sum+=((ll)(n/i)*(m/i)*(mbs[last][p]-mbs[i-1][p]));
}
printf("%I64d\n",sum);
}
}
return 0;
}