[BZOJ 2301][HAOI2011]Problem b(莫比乌斯反演)
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
Solution
还是要学习一个
莫比乌斯反演…
进行优化,对mu维护一个前缀和
学习资料的话推荐PoPoQQQ的ppt,还有莫比乌斯反演(宋新波)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #define MAXN 50005 #define Min(a,b) (a<b?a:b) using namespace std; typedef long long LL; int n,a,b,c,d,k; int mu[MAXN],sum[MAXN],pri[MAXN],cnt=0; bool jud[MAXN]; void getmu() { mu[1]=1; for(int i=2;i<=MAXN;i++) { if(!jud[i])pri[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt&&pri[j]*i<=MAXN;j++) { jud[pri[j]*i]=1; if(i%pri[j]==0){mu[pri[j]*i]=0;break;} mu[pri[j]*i]=-mu[i]; } } for(int i=1;i<=MAXN;i++) sum[i]=sum[i-1]+mu[i]; } LL clac(int m,int n,int k) { LL res=0;int last; m/=k,n/=k; for(int i=1;i<=Min(n,m);i=last+1) { last=min(n/(n/i),m/(m/i)); res+=(LL)(n/i)*(m/i)*(sum[last]-sum[i-1]); } return res; } int main() { scanf("%d",&n);getmu(); for(int i=1;i<=n;i++) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%lld\n",clac(b,d,k)-clac(a-1,d,k)-clac(b,c-1,k)+clac(a-1,c-1,k)); } return 0; }