(Luogu2522)
题目大意:求下面式子的值:
[sum_{i=x}^nsum_{j=y}^m[gcd(i,j)=k]
]
这个东西直接求不好求,考虑差分,从([1,n])的范围求,然后相减。
那么考虑:
[sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=k]
]
同时除以(k):
[sum_{i=1}^{frac{n}{k}}sum_{j=1}^{frac{m}{k}}[gcd(i,j)=1]
]
枚举(d|gcd(i,j)),套上反演套路,并且将(d)提到前面:
[sum_{i=1}^{frac{n}{k}}sum_{j=1}^{frac{m}{k}}sum_{d|gcd(i,j)}mu(d)
]
[=sum_{d=1}^{n}mu(i)sum_{i=1}^{frac{n}{kd}}sum_{j=1}^{frac{m}{kd}}
]
[=sum_{d=1}^{n}mu(i)frac{n}{kd}frac{m}{kd}
]
这玩意到此结束,后面数论分块即可,(O(sqrt{n})).
套一个差分即可。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=6e4+10;
int n,m;
int prime[MAXN],mu[MAXN];
int fg[MAXN],tot,sum[MAXN];
void screen(){
mu[1]=1;
for(int i=2;i<=MAXN;++i){
if(!fg[i])prime[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*prime[j]<=MAXN;++j){
fg[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<=MAXN;++i)sum[i]=sum[i-1]+mu[i];
}
int solve(int x,int y,int k){
int ans=0,M;
M=min(x,y);
for(int l=1,r;l<=M;l=r+1){
r=min(x/(x/l),y/(y/l));
ans+=(x/(l*k))*(y/(l*k))*(sum[r]-sum[l-1]);
}
return ans;
}
int main(){
scanf("%d",&n);
screen();
for(;n;n--){
int k,a,b,c,d;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("%d
",solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k));
}
return 0;
}