计蒜客 ICPC徐州网络赛 Easy Math(Min25筛)

版权声明:本文为博主原创文章,转载请著名出处 http://blog.csdn.net/u013534123 https://blog.csdn.net/u013534123/article/details/82598558

大致题意:让你求 \sum_{i=1}^{m}\mu(in)

根据莫比乌斯函数的定义,对于mu(i)如果i可以分解为任意一个质数的平方分解,那么函数值为0。所以对于这个求和的式子来说,i有意义,当且仅当gcd(i,n)==1。而根据莫比乌斯函数的积性,当gcd(i,n)==1时,有\mu(in)=\mu(i)\mu(n)。所以说这个mu(n)完全可以提取到外面,这样求和式子就是:

                                             \large ans=\mu(n)*\sum_{i=1}^{m}\mu(i)[gcd(i,n)==1]

显然,如果mu(n)==0,那么答案也是0。现在考虑mu(n)!=0的时候怎么计算。

这是一个积性函数的求和,只不过是去掉了某些项。然后这个积性函数的质数幂为0,很好算,取质数时的函数值也可以用多项式表示,符合Min25筛的条件,所以可以考虑用Min25筛来做。

Min25筛了解一下:https://blog.csdn.net/u013534123/article/details/82596172

Min25筛分为三个部分,一个是质数部分,一个是合数部分,最后是1。质数部分,就是质数的莫比乌斯函数之和,而质数对应的莫比乌斯函数是-1,所以相当于是求1..n中质数个数再乘以-1即可。但不管怎么说我们还是要按照Min25筛的套路来。我们令g(n,j)表示从1到n所有的i中,满足要么i自己是质数,要么i的最小质因子大于第j个质数的数字个数。然后带入递推公式:

             \large g(m,j)= \begin{cases} g(m,j-1) & P_j^2 > m \\ g(m,j-1)-F(P_j)[g(m/P_j,j-1)-g(P_j-1,j-1)] & P_j^2\le m \end{cases}

这里的F(Pj)就是mu(Pj),g(P_{j}-1,j-1)等于\sum_{i=1}^{j-1}F(P_i)也即\sum_{i=1}^{j-1}\mu(P_i)=-j+1。这样式子就是

             \dpi{120} \large g(m,j)= \begin{cases} g(m,j-1) & P_j^2 > m \\ g(m,j-1)-[g(m/P_j,j-1)+j-1] & P_j^2\le m \end{cases}

质数部分解决,然后看总共的。令S(n,j)表示从1累加到n的mu(i),同样的,i要么是质数,要么最小质因子大于第j个质数。带入公式有:

                                      S(m,j)=g(m,|P|)+j-1-\sum_{k\ge j}S(\frac{m}{P_k},k+1)

但是机智的读者可能发现这个是不对的。如果我们知识求mu(i)的前缀和,这样没问题,但是我们现在算的对于i是有条件的,所以说我们得减去一些不合法的i,也即gcd(i,n)>1的i。而这里只要我们做到在选取质数的时候不选取n的质因子即可,所以我们可以改一下这个式子,不妨设在n有x个大于等于Pj的质因子,那么有式子:

                          S(m,j)=g(m,|P|)+j-1-x-\sum_{k\ge j,P_k \nmid n}S(\frac{m}{P_k},k+1)

最后再加上i为1的结果就是最后答案。具体见代码:

#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define INF 0x3f3f3f3f
#define sf(x) scanf("%lld",&x)
#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;

const int N = 1e6 + 10;
const int inv = 5e8 +4;

LL p[N],w[N],pri[N],g[N],M,m,n;
int block,id[N],sz,tot;
bool isp[N],v[N];

void init(int n)
{
    sz=0;
    for(int i=2;i<=n;i++)
    {
        if(!isp[i])p[++sz]=i;
         for(int j=1;j<=sz&&p[j]*i<n;j++)
         {
            isp[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}

void sieve_g(LL n)
{
    M=0;
    for(LL i=1,last;i<=n;i=last+1)
    {
        LL len=n/i; last=n/len;
        w[++M]=len; g[M]=1-w[M];
        if(len<=block) id[len]=M;
    }
    for(int i=1;i<=sz;i++)
        for(int j=1;j<=M&&p[i]*p[i]<=w[j];j++)
        {
            int op=w[j]/p[i]<=block?id[w[j]/p[i]]:n/(w[j]/p[i]);
            g[j]-=g[op]+i-1;
        }
}

LL S(LL x,LL y)
{
    LL k,res=0;
    if (x<=1||p[y]>x) return 0;
    if (x>block) k=m/x; else k=id[x];
    res=g[k]+y-1;                           //part of prime sum
    for(int i=1;i<=tot&&pri[i]<=w[k];i++)
        if (pri[i]>p[y-1]) res++;
    for(int i=y;i<=sz&&p[i]*p[i]<=x;i++)
        if (v[i]==0) res-=S(x/p[i],i+1);
    return res;
}

int main()
{
    tot=0;
    sf(m); sf(n);
    block=ceil(sqrt(m));
    init(m<=1e6?1e4:1e6); sieve_g(m);
    for(int i=1;p[i]*p[i]<=n&&i<=sz;i++)
    {
        if (n%p[i]) continue;
        pri[++tot]=p[i]; n/=p[i]; v[i]=1;
        if (n%p[i]==0) {puts("0");return 0;}
    }
    if (n>1)
    {
        pri[++tot]=n;
        for(int i=1;i<=sz;i++)
            if (p[i]==n) {v[i]=1;break;}
    }
    int t=tot&1?-1:1;
    printf("%lld\n",(S(m,1)+1)*t);
    return 0;
}

 

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/82598558
今日推荐