BZOJ2301: [HAOI2011]Problem b 莫比乌斯反演
分析:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
然后对于求这样单个的gcd(x,y)=k的,我们通常采用莫比乌斯反演
但是,时间复杂度是O(n*(n/k))的,当复杂度很坏的时候,当k=1时,退化到O(n^2),超时
然后进行分块优化,时间复杂度是O(n*sqrt(n))
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int N=5e4+5; const int INF=0x3f3f3f3f; bool vis[N]; int prime[N],mu[N],cnt; void getmu() { mu[1] = 1; for(int i=2; i<=N-5; i++) { if(!vis[i]) { prime[++cnt] = i; mu[i] = -1; } for(int j=1; j<=cnt&&i*prime[j]<=N-5; j++) { vis[i*prime[j]] = 1; if(i%prime[j]) mu[i*prime[j]] = -mu[i]; else { mu[i*prime[j]] = 0; break; } } } } LL solve(int n,int m,int k){ n/=k,m/=k; int l=min(n,m); LL ans=0; for(int i=1,j;i<=l;i=j+1){ j=min(n/(n/i),m/(m/i)); ans+=1ll*(mu[j]-mu[i-1])*(n/i)*(m/i); } return ans; } int main(){ getmu(); for(int i=1;i<=N-5;++i)mu[i]+=mu[i-1]; int T; scanf("%d",&T); while(T--){ int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%lld\n",solve(b,d,k)-solve(b,c-1,k)-solve(a-1,d,k)+solve(a-1,c-1,k)); } return 0; }