题意:问i:1~n j:1~m中有多少个gcd(i,j)==k的组合,gcd(5,7)与gcd(7,5)算一种
莫比乌斯函数套路题,做过无数遍了= =莫比乌斯算这种(i,j)( j,i)是算两种的,注意!
对于i:1~n j:1~n中gcd(i,j) gcd(j,i)算了两边,所以要多算一遍1~n 1~n,除二后减去就好了
15ms
#include <cstring>
#include<iostream>
using namespace std;
#define ll long long
const int N=1e6+5;
int prime[N],primesize,mu[N];
int sum[N];
bool isprime[N];
//线性筛可以预处理prime和isprime
//在这过程中可以预处理积性函数f, 比如mu phi d
//4个加代码的地方要自己加 要取模就每一步都取模
//比如预处理欧拉函数 预处理mu,均有模板
//反演的题会用到这个
//prime从prime[1]开始
void getlist(int listsize)//预处理的范围 指i*prime[j]的最大值
{
memset(isprime,1,sizeof(isprime));
isprime[1]=false;
mu[1]=1;
mu[0]=0;
//A从2开始,所以这里加f(1)=?;
for(int i=2; i<=listsize; i++)
{
if(isprime[i])
{
prime[++primesize]=i;
//B加代码 质数的情况
mu[i]=-1;
}
//这里的prime[j]一定是最小质因子
for(int j=1; j<=primesize&&i*prime[j]<=listsize; j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j]==0)
{
//C加代码 不互素的情况 一般考虑f(p^k)与p的关系
mu[i*prime[j]] = 0;
break;
}
else
{
//D加代码 互素的情况
mu[i*prime[j]] = -mu[i];
}
}
//E可加前缀和代码
mu[i]+=mu[i-1];
}
// sum[0]=0;
// for(int i=1; i<=N; i++)
// sum[i]=mu[i]+sum[i-1];
}
int main()
{
getlist(N);
int T=0;
scanf("%d",&T);
int kase=0;
while(T--)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("Case %d: ",++kase);
if(k==0)
{
printf("0\n");
continue;
}
b=b/k;
d=d/k;
if(b>d)
swap(b,d);
ll ans=0;
int next=0;
for(int i=1; i<=b; i=next+1)
{
next=min(b/(b/i),d/(d/i));//分块套路
ans+=1ll*(b/i)*(d/i)*(mu[next]-mu[i-1]);
}
next=0;
ll ans2=0;
for(int i=1; i<=b; i=next+1)
{
next=b/(b/i);
ans2+=1ll*(b/i)*(b/i)*(mu[next]-mu[i-1]);
}
cout<<ans-ans2/2<<endl;
}
}