【Luogu】P2303Longge的问题(莫比乌斯反演)
就让我这样的蒟蒻发一个简单易想的题解吧!!!
这题我一开始一看,woc这不是莫比乌斯反演么,推推推,推到杜教筛,输出结果一看不对
emmm回来仔细想想……woc推错了?
然后撕烤半天打了个暴力,A了
首先我们学过莫比乌斯反演的一般能够想到枚举gcd,记为w
所以我们需要求的就是$\sum\limits_{w|n}w\sum\limits_{w|i}[gcd(i,n)=w]$
然后……就到了激动人心的构造函数环节……
设$F(w)=\sum\limits_{w|i}[w|gcd(i,n)]$
$f(w)=\sum\limits_{w|i}[w=gcd(i,n)]$
于是有$F(w)=\sum\limits_{w|d}f(d)$
于是……$f(w)=\sum\limits_{w|d}\mu(\frac{d}{w})F(d)$
容易(个屁,我手玩了半年)发现,当$d|n$时$F(d)=\frac{n}{d}$,其他情况下$F(d)=0$
然后问题就变成了$\sum\limits_{w|n}w\sum\limits_{w|d}\mu(\frac{d}{w})F(d)$
设$t=\frac{d}{w}$
原式化为$\sum\limits_{w|n}w\sum\limits_{t|d}\mu(t)F(tw)$
然后我们发现了什么?
没错w可以暴力枚举qwq!没错t可以暴力枚举qwq!
因为我们枚举到根n就可以枚举出n的所有因子! t同理!
来吧让我们暴……等等$\mu$怎么算?
废话啊按着莫比乌斯函数的定义暴力qwq!
#include<cstdio> #include<algorithm> #include<cstring> #include<cctype> #include<cstdlib> #include<iostream> #include<cmath> #define maxn 5000020 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } bool vis[maxn]; int prime[maxn],tot; int mu[maxn]; inline int calcmu(long long n){ if(n<maxn) return mu[n]; long long sqt=sqrt(n); long long now=n;int ans=0; for(int j=1;j<=tot;++j){ int i=prime[j]; if(i>sqt) break; if(now%i) continue; int cnt=0; while((now%i)==0){ cnt++; now/=i; if(cnt>1) return 0; } ans++; } if(now>0) ans++; if(ans&1) return -1; else return 1; } int main(){ mu[1]=vis[1]=1; for(int i=2;i<maxn;++i){ if(vis[i]==0){ prime[++tot]=i; mu[i]=-1; } for(int j=1;j<=tot&&prime[j]*i<maxn;++j){ vis[i*prime[j]]=1; if(i%prime[j]) mu[i*prime[j]]=-mu[i]; else break; } } long long n=read(),ans=0; int sqt=sqrt(n); for(int i=1;i<=sqt;++i){ if(n%i) continue; long long d=n/i;long long now=0; long long sar=sqrt(d); for(int j=1;j<=sar;++j){ if(d%j) continue; now+=calcmu(j)*(n/(j*i)); if(j*j==d) continue; now+=calcmu(d/j)*(n/((d/j)*i)); } ans+=now*i; if(1LL*i*i==n) continue; long long ret=n/i; d=n/ret;now=0; sar=sqrt(d); for(int j=1;j<=sar;++j){ if(d%j) continue; now+=calcmu(j)*(n/(j*ret)); if(j*j==d) continue; now+=calcmu(d/j)*(n/((d/j)*ret)); } ans+=now*ret; } printf("%lld\n",ans); return 0; }