[ACM-ICPC 2018 徐州赛区网络预赛][D. Easy Math]

题目链接:Easy Math

题目大意:给定\(n(1\leqslant n\leqslant 10^{12}),m(1\leqslant m\leqslant 2*10^{9})\),求\(\sum_{i=1}^{m}\mu (i\cdot n)\)。

题解:废话少说,直接上公式

$$\mu(i\cdot n)=\left\{\begin{matrix}
\mu(i)\cdot\mu(n) & gcd(i,n)==1\\
0 & other
\end{matrix}\right.$$

$$F(n,m)=\sum_{i=1}^{m}\mu(i\cdot n)$$

则有$$F(n,m)=\mu(n)\cdot\sum_{i=1}^{m}\mu (i)\cdot[gcd(i,n)==1]$$

由$$[n==1]=\sum_{d|n}^{ } \mu(d)$$

$$F(n,m)=\mu(n)\cdot\sum_{i=1}^{m}\mu (i)\sum_{d|gcd(i,n)}^{ }\mu(d)$$

$$F(n,m)=\mu(n)\cdot\sum_{d|n}^{d\leqslant m}\mu(d)\cdot\sum_{i=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\mu(i\cdot d)$$

$$F(n,m)=\mu(n)\cdot\sum_{d|n}^{d\leqslant m}\mu(d)\cdot F(d,\left \lfloor \frac{m}{d} \right \rfloor)$$

推出式子后,递归求解即可,当n==1时,有\(F(n,m)=M(m)=\sum_{i=1}^{m}\mu(i)\),关于这个式子有一个莫比乌斯反演的经典公式,就是$$M(n)=1-\sum_{i=2}^{n}M(\left \lfloor \frac{n}{i} \right \rfloor)$$预处理出莫比乌斯函数及其前缀和的值后即可,求M(n)的时候记得要分块做

#include<bits/stdc++.h>
using namespace std;
#define N 10000001
#define LL long long
LL n,m,cnt,p[N],f[N],s[N];
map<LL,LL>M;
bool x[N];
void pretype()
{
    f[1]=1;
    for(int i=2;i<N;i++)
      {
      if(!x[i])p[++cnt]=i,f[i]=-1;
      for(int j=1;j<=cnt && i*p[j]<N;j++)
        {
        f[i*p[j]]=-f[i];
        x[i*p[j]]=true;
        if(i%p[j]==0){f[i*p[j]]=0;break;}
        }
      }
    for(int i=1;i<N;i++)
      s[i]=s[i-1]+f[i];
}
LL get(LL n)
{
    if(n<N)return f[n];
    LL k=1;
    for(LL i=2;i*i<=n;i++)
      if(n%i==0)
        {
        if(n%(i*i)==0)return 0;
        k*=-1,n/=i;
        }
    if(n>1)k*=-1;return k;
}
LL get_M(LL n)
{
    if(n<N)return s[n];
    if(M[n])return M[n];
    LL res=1,nxt;
    for(LL i=2;i<=n;i=nxt+1)
      {
      nxt=min(n,n/(n/i));
      res-=(nxt-i+1)*get_M(n/i);
      }
    return M[n]=res;
}
LL F(LL n,LL m)
{
    if(n==1)return get_M(m);
    LL miu=get(n),res=0;
    if(miu==0)return 0;
    for(LL d=1;d*d<=n && d<=m;d++)if(n%d==0)
      {
      res+=get(d)*F(d,m/d);
      if(n/d<=m)res+=get(n/d)*F(n/d,m/(n/d));
      }
    return miu*res;
}
int main()
{
    pretype();
    scanf("%lld%lld",&m,&n);
    printf("%lld\n",F(n,m));
}
View Code

 

posted @ 2018-09-09 19:08  DeaphetS  阅读(659)  评论(3编辑  收藏  举报