题目大意:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。 数据范围:100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
询问可以用容斥来解决,就转换成了那个题了:1<=x<=n,1<=y<=m 和上次那个题差不多,还是推公式。 传送门 预处理莫比乌斯函数前缀和,可以根号处理询问,因为那一坨只有 n√ 个取值。 代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #define ll long long using namespace std; int mu[50001]; int vis[50001]; int prime[50001]; int cnt; void init(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]){ prime[++cnt]=i; mu[i]=-1; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ int k=i*prime[j]; vis[k]=1; if(i%prime[j]){ mu[k]=-mu[i]; } else{ mu[k]=0; break; } } mu[i]+=mu[i-1]; } } inline ll solve(int n,int m,int k){ n/=k; m/=k; ll ans=0; int lim=min(n,m); for(int i=1,j;i<=lim;i=j+1){ j=min(n/(n/i),m/(m/i)); ans+=(ll)(n/i)*(ll)(m/i)*(ll)(mu[j]-mu[i-1]); } return ans; } int t; int a,b,c,d,k; int main(){ init(50000); scanf("%d",&t); while(t--){ scanf("%d %d %d %d %d",&a,&b,&c,&d,&k); printf("%lld\n",solve(b,d,k)+solve(a-1,c-1,k)-solve(a-1,d,k)-solve(b,c-1,k)); } return 0; }