洛谷ios
首先題目給定的限制是\(\sum_{n|i}a[i]=\mu(n)\),而後把這個東西反演一下,
莫比烏斯反演的式子是:\(g(n)=\sum_{n|i}f(i)\rightarrow f(n)=\sum_{n|i}g(i)\mu(\frac{i}{n})\),在這裏\(\mu\)就是\(g\),而\(a\)就是\(f\)。
因此咱們能夠獲得:\(a[m]=\sum_{m|i}\mu(i)\mu(\frac{i}{m})=\sum_{i=1}^{n/m}\mu(i)\mu(im)\)。
而後直接把後面拆開,獲得:\(\mu(m)\sum_{i=1}^{n/m}[gcd(i,m)=1]\mu(i)^2\)
後面那一半接着拆,能夠獲得:
\[\begin{aligned} a[m]&=\mu(m)\sum_{i=1}^{n/m}\mu(i)^2\sum_{j|i,j|m}\mu(j)\\ &=\mu(m)\sum_{j|m}\mu(j)\sum_{j|i}^{n/m}\mu(i)^2 \end{aligned}\]
前面的\(j\)顯然只有\(\sqrt m\) 個了。
後面一半枚舉最小的平方因子,而後把這部分的貢獻減去就好了,這部分的複雜度是\(O(\sqrt \frac{n}{m})\)。
因此總的複雜度就是\(O(\sigma_0(m)\sqrt{\frac{n}{m}})\)。spa
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define ll long long inline ll read() { ll x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } ll n,ans;int m,fac[100],p;; const int N=1e6; bool zs[N]; int mu[N],pri[N],tot; void Sieve() { mu[1]=1; for(int i=2;i<N;++i) { if(!zs[i])pri[++tot]=i,mu[i]=-1; for(int j=1;j<=tot&&i*pri[j]<N;++j) { zs[i*pri[j]]=true; if(i%pri[j]==0)break; mu[i*pri[j]]=-mu[i]; } } } void Calc(int j,int v) { int nn=n/m/j,ret=0; for(int i=1;i*i<=nn*j;++i) { int ii=i*i/__gcd(i*i,j); ret+=nn/ii*mu[i]; } ans+=v*ret; } void dfs(int x,int j,int mu) { if(x==p+1){Calc(j,mu);return;} dfs(x+1,j,mu); dfs(x+1,j*fac[x],-mu); } int main() { int T=read();Sieve(); while(T--) { n=read();m=read();p=ans=0; int x=m;bool fl=false; for(int i=2;i*i<=x;++i) if(x%i==0) { int c=0;fac[++p]=i; while(x%i==0)++c,x/=i; if(c>1){fl=true;break;} } if(fl){puts("0");continue;} if(x>1)fac[++p]=x; dfs(1,1,1); printf("%lld\n",ans*((p&1)?-1:1)); } }