Description
题目描述
对于给出的 n 个询问,每次求有多少个数对 (x,y),满足 a≤x≤b,c≤y≤d,且 gcd(x,y)=k ,
gcd(x,y) 函数为 x 和 y 的最大公约数。
输入格式
第一行一个整数 n,接下来 n 行每行五个整数,分别表示 a,b,c,d,k。
输出格式
共 n 行,每行一个整数表示满足要求的数对 (x,y) 的个数。
Soluiton
入门资料-莫比乌斯反演讲解(里面有这道题的详细解答)
先用容斥把它分成四个 x , y 取值下界为1的子问题,然后用莫比乌斯反演
Code
#include <cstdio> #include <cstdlib> #include <algorithm> #define ll long long using namespace std; const int N=5e4,M=5e4+10; int vis[M],u[M],a,b,c,d,k,t,prime[M],tot; inline char get() { static char buf[1024]; static int pos=0,size=0; if(pos==size) { size=fread(buf,1,1024,stdin); pos=0; if(!size) return EOF; else return buf[pos++]; } else return buf[pos++]; } int read() { int sum=0,fh=1; char ch=get(); while(!(ch>='0' && ch<='9')) { if(ch=='-') fh=-1; ch=get(); } while(ch>='0' && ch<='9' && ch!=EOF) sum=sum*10+ch-48,ch=get(); return sum*fh; } inline ll solve(int a,int b) { ll ans=0; a/=k,b/=k; int boun=min(a,b); for(int l=1,r;l<=boun;l=r+1) { r=min(a/(a/l),b/(b/l)); ans+=1ll*(u[r]-u[l-1])*(a/l)*(b/l); } return ans; } int main() { u[1]=1; for(int i=2;i<=N;i++) { if(!vis[i]) { prime[++tot]=i; u[i]=-1; } for(int j=1;j<=tot && prime[j]<=N/i;j++) { vis[prime[j]*i]=1; if(i%prime[j]==0) break; else u[prime[j]*i]=-u[i]; } u[i]+=u[i-1]; } t=read(); while(t--) { a=read(),b=read(),c=read(),d=read(),k=read(); printf("%lld\n",solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1)); } return 0; }