莫比乌斯反演的一些东西:
莫比乌斯反演定理
或
莫比乌斯函数:
【题解】
用容斥的思想:
Ans( a<=x<=b , c<=y<=d ) = Ans( 1<=x<=b , 1<=y<=d ) - Ans( 1<=x<=a-1 , 1<=y<=d ) - Ans( 1<=x<=b , 1<=y<=c-1 ) + Ans( 1<=x<=a-1 , 1<=y<=c-1 )
那么对于转化后的每个询问:1<=x<=n,1<=y<=m,gcd(x,y)=k的(x,y)个数
设f(k)为答案,F(k)表示 1<=x<=n,1<=y<=m,k|gcd(x,y)的(x,y)个数,则:
F(k)=sigma( f(d) ) , k|d,又 F(k)=[n/k]*[m/k]
=> f(k)=sigma( mu(d/k)*F(d) ) , k|d
=sigma( mu(d/k)*[n/d]*[m/d] ) , k|d
直接枚举d,复杂度为线性,会超时
而对于某些d,[n/d1]=[n/d2],[n/d]最多有2*sqrt(n)个取值
那么 [n/d]*[m/d]最多有 2*sqrt(n)+2*sqrt(m) 个取值
枚举d时,计算出 d2>=d 且 [n/d2]*[m/d2]=[n/d]*[m/d] 的最大d2值,d与d2之间的的都不改变F值,直接跳过即可,前缀和处理mu[]
复杂度为O(n*sqrt(n))
【代码】
#include<stdio.h> #include<stdlib.h> typedef long long LL; int no[50005],pri[50005],mu[50005]; int k; int min(int a,int b) { if(a<b) return a; return b; } LL ask(int n,int m) { LL ans=0; int i,last; for(i=1;i*k<=n&&i*k<=m;i=last+1)//枚举:d=i*k { last=min( n/(n/(i*k)) , m/(m/(i*k)) )/k;// i*k~last*k 代入 d:[n/d]*[m/d]均不变 ans+=(LL)(mu[last]-mu[i-1])*(LL)(n/(i*k))*(LL)(m/(i*k)); } return ans; } int main() { int n,a,b,c,d,i,j,p=0; scanf("%d",&n); mu[1]=1; for(i=2;i<=50000;i++) { if(no[i]==0) { pri[++p]=i; mu[i]=-1; } for(j=1;j<=p&&pri[j]*i<=50000;j++) { no[pri[j]*i]=1; if(i%pri[j]==0) break; mu[pri[j]*i]=-mu[i]; } } for(i=2;i<=50000;i++) mu[i]+=mu[i-1]; for(;n>0;n--) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%lld\n",ask(b,d)-ask(a-1,d)-ask(b,c-1)+ask(a-1,c-1)); } return 0; }