首页 > 代码库 > SPOJ : DIVCNT2 - Counting Divisors (square)

SPOJ : DIVCNT2 - Counting Divisors (square)

\[f(n)=\sum_{d|n}\mu^2(d)\]

\[\begin{eqnarray*}
\sigma_0(n^2)&=&\sum_{d|n}f(d)\\
ans&=&\sum_{i=1}^n\sigma_0(i^2)\\
&=&\sum_{i=1}^n\sum_{d|i}\sum_{k|d}\mu^2(k)\\
&=&\sum_{k=1}^n\mu^2(k)G(\lfloor\frac{n}{k}\rfloor)
\end{eqnarray*}\]

其中

\[G(n)=\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\]

又因为

\[\sum_{i=1}^n\mu^2(i)=\sum_{i=1}^{\sqrt{n}}\mu(i)\lfloor\frac{n}{i^2}\rfloor\]

因此首先线性筛预处理出$n^{\frac{2}{3}}$内的所有答案,然后分段计算即可。

时间复杂度$O(Tn^{\frac{2}{3}})$。

 

#include<cstdio>typedef long long ll;const int N=100000010;int T,M,tot,p[N/10],f[N];char v[N],mu[N],h[N];ll g[N],n,m,o,a[10010],old,now,ans,i,j;inline ll F(ll n){  if(n<M)return f[n];  ll ret=0;  for(ll i=1;i<=n/i;i++)ret+=n/i/i*mu[i];  return ret;}inline ll G(ll n){  if(n<M)return g[n];  ll ret=0;  for(ll i=1,j;i<=n;i=j+1){    j=n/(n/i);    ret+=n/i*(j-i+1);  }  return ret;}void init(){  int i,j,k;  for(mu[1]=g[1]=1,i=2;i<M;i++){    if(!v[i])mu[i]=-1,g[i]=h[i]=2,p[tot++]=i;    for(j=0;j<tot&&i*p[j]<M;j++){      v[k=i*p[j]]=1;      if(i%p[j]){        mu[k]=-mu[i];        g[k]=g[i]*2;        h[k]=2;      }else{        g[k]=g[i]/h[i]*(h[i]+1);        h[k]=h[i]+1;        break;      }    }  }  for(i=1;i<M;i++)f[i]=f[i-1]+(mu[i]!=0),g[i]+=g[i-1];}int main(){  scanf("%d",&T);  for(o=1;o<=T;o++){    scanf("%lld",&a[o]);    if(a[o]>m)m=a[o];  }  if(m<=1000000)M=m;else{    for(M=1;1LL*M*M*M<m;M++);    M*=M;  }  init();  for(o=1;o<=T;o++){    n=a[o];    ans=old=0;    for(i=1;i<=n;i=j+1){      now=F(j=n/(n/i));      ans+=(now-old)*G(n/i);      old=now;    }    printf("%lld\n",ans);  }  return 0;}

  

SPOJ : DIVCNT2 - Counting Divisors (square)