LG3455[POI2007]ZAP-Queries【整除分塊+莫比烏斯反演】
阿新 • • 發佈:2019-01-11
LG3455[POI2007]ZAP-Queries【整除分塊+莫比烏斯反演】
前置知識:整除分塊
整除分塊
注:以下內容來自洛谷
題目大意
- 求$\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(x,y)=d]$
- 多組輸入
- $1\le d\le a,b\le 50000$
解題思路
\[f(k)=\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)=k]\]
\[F(n)=\sum_{n|k}f(k)=\lfloor\frac{a}{n}\rfloor\lfloor\frac{b}{n}\rfloor\]
則可以由莫比烏斯反演可以推出:
\[f(n)=\sum_{n|k}\mu(\lfloor\frac{k}{n}\rfloor)F(k)\]
\[Ans=\sum_{d|k}\mu(\lfloor\frac{k}{d}\rfloor)F(k)\]
列舉\(\lfloor\frac{k}{d}\rfloor\)設為\(t\)
\[Ans=\sum_{t=1}^{min(a,b)}\mu(t)\lfloor\frac{a}{td}\rfloor\lfloor\frac{b}{td}\rfloor\]
這時候,這個式子已經可以做到\(O(n)\)的時間複雜度了,但是因為有多組資料,所以我們再用一下整除分塊,這題就可以做到\(O(\sqrt{n})\)了。
貼上程式碼:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int MX=50005,N=50505; inline void Read(int &x){ x=0;register char cc='\0';int fff=1; for(;cc<'0'||cc>'9';cc=getchar())if(cc=='-')fff=-1; for(;cc>='0'&&cc<='9';cc=getchar())x=(x<<1)+(x<<3)+(cc&15); x*=fff; } bool Pr[N]; int n,a,b,d,tot,p[N],mu[N]; void Prepare(){ Pr[0]=Pr[1]=true;mu[1]=1; for(int i=2;i<=MX;++i){ if(!Pr[i]){p[++tot]=i;mu[i]=-1;} for(int j=1;j<=tot&&i*p[j]<=MX;++j){ Pr[i*p[j]]=true; if(i%p[j]==0)break; mu[i*p[j]]=mu[i]*mu[p[j]]; } } for(int i=2;i<=MX;++i) mu[i]+=mu[i-1]; } int main() { freopen("LG3455.in","r",stdin); freopen("LG3455.out","w",stdout); Read(n); Prepare(); while(n--){ Read(a);Read(b);Read(d); a/=d;b/=d;if(a>b)swap(a,b); long long ans=0; for(int i=1,j=1;i<=a;i=j+1){ j=min(a/(a/i),b/(b/i)); ans+=1LL*(mu[j]-mu[i-1])*(a/i)*(b/i); } printf("%lld\n",ans); } return 0; }