BZOJ 1101: [POI2007]Zap(莫比乌斯反演)

传送门

解题思路

  $$
\sum\limits_{i=1}n\sum\limits_{j=1}mgcd(i,j)=k

\[ \]

\sum\limits_{i=1}{\frac{n}{m}}\sum\limits_{j=1}{k}}gcd(i,j)=1

\[ \]

\sum\limits_{i=1}{\frac{n}{k}}\sum\limits_{j=1}{k}}\sum\limits_{d|n,d|m}\mu(d)

\[ \]

\sum\limits_{i=1}{n}\mu(d)\sum\limits_{i=1}{kd}}\sum\limits_{j=1}^{\frac{m}{kd}}

\[   然后这样就做完了,$\mu$搞一个前缀和,其余的整除分块 ##代码 ```cpp #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; } ```\]

posted @ 2019-01-13 09:57  Monster_Qi  阅读(146)  评论(0编辑  收藏  举报