BZOJ 1101: [POI2007]Zap(莫比烏斯反演)
阿新 • • 發佈:2019-01-13
解題思路
\[ \sum\limits_{i=1}^n\sum\limits_{j=1}^mgcd(i,j)=k \]
\[ \sum\limits_{i=1}^{\frac{n}{m}}\sum\limits_{j=1}^{\frac{m}{k}}gcd(i,j)=1 \]
\[ \sum\limits_{i=1}^{\frac{n}{k}}\sum\limits_{j=1}^{\frac{m}{k}}\sum\limits_{d|n,d|m}\mu(d) \]
\[ \sum\limits_{i=1}^{n}\mu(d)\sum\limits_{i=1}^{\frac{n}{kd}}\sum\limits_{j=1}^{\frac{m}{kd}} \]
然後這樣就做完了,\(\mu\)搞一個字首和,其餘的整除分塊
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN = 50005; typedef long long LL; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return f?x:-x; } int n,miu[MAXN]={0,1},prime[MAXN],cnt,ans; bool vis[MAXN]; int main(){ for(int i=2;i<=50000;i++){ if(!vis[i]) {prime[++cnt]=i;miu[i]=-1;} for(int j=1;j<=cnt && prime[j]*i<=50000;j++){ vis[i*prime[j]]=1; if(!(i%prime[j])) {miu[i*prime[j]]=0;break;} miu[i*prime[j]]=-miu[i]; } } for(int i=1;i<=50000;i++) miu[i]+=miu[i-1]; n=rd();int a,b,d; while(n--){ a=rd(),b=rd(),d=rd();if(a>b) swap(a,b); for(int l=1,r;l<=a/d;l=r+1){ r=min((a/d)/(a/d/l),(b/d)/(b/l/d)); ans+=(miu[r]-miu[l-1])*(a/l/d)*(b/l/d); } printf("%d\n",ans);ans=0; } return 0; }