【数论】线性筛&积性函数

线性筛

线性筛素数

#define MAXN 1000000
int prim[MAXN],vis[MAXN],c;
void Solve()
{
    mu[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(!vis[i])
            prim[c++]=i;
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            vis[i*prim[j]]=1;
            if(i%prim[j]==0)
                break;
        }
    }
}

一些理解
1.一个合数 A = p 1 k 1 p 2 k 2 p c k c ( p 1 < p 2 < < p c ) 被筛出来时, p r i m [ j ] = p 1 ;
2.当满足 if ( i % p r i m [ j ] == 0 ) break 时,合数 i p r i m [ j ] 还没有被筛出来。
i 1 = i p r i m [ j ] p r i m [ j + 1 ] ,内层循环枚举到 p r i m [ j ] 时,才会被筛出。

积性函数

欧拉函数

ϕ ( n ) = i = 1 n [ g c d ( i , n ) = 1 ] = n ( 1 1 p 1 ) ( 1 1 p 2 ) ( 1 1 p k )
即小于等于x并且和x互质的数的个数

性质

1:(积性函数) ϕ ( a b ) = ϕ ( a ) ϕ ( b ) ,其中gcd(a,b)=1;
2: d | n ϕ ( d ) = n
3:小于 n 且与 n 互质的数的和: s u m = n ϕ ( n ) 2
证明:显然,若 m n 互质,则 ( n m ) n 互质(由辗转相除法可知)
n > 2 时, ϕ ( n ) 为偶数,也就是说 m n m 成对出现,有 ϕ ( n ) 2 对,此时 s u m = n ϕ ( n ) 2
n 2 时,该式成立。

线性筛欧拉函数
int phi[MAXN],prim[MAXN],c;
void Solve()
{
    phi[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(!phi[i])
        {
            prim[c++]=i;
            phi[i]=i-1;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            if(i%prim[j]==0)
            {
                phi[i*prim[j]]=prim[j]*phi[i];
                break;
            }
            phi[i*prim[j]]=(prim[j]-1)*phi[i];
        }
    }
}
补充:当我们只需要求某一个数的 ϕ ( n ) , n 10 12 ,可用以下筛法

要预处理出 10 6 以内素数。
时间复杂度:O( n )

LL Solve(LL n)
{
    LL ret=n;
    for(int i=0;i<tot&&prim[i]<=n;i++)
        if(n%prim[i]==0)
        {
            ret=ret/prim[i]*(prim[i]-1);
            while(n%prim[i]==0) n/=prim[i];
        }
    if(n!=0) ret=ret/n*(n-1);
    return ret;
}

莫比乌斯函数

μ (1)=1
μ (d)= ( 1 ) k , d = p 1 p 2 p 3 p k ,其中 p 为素数
μ (d)=0,其他

性质

1:(积性函数) μ ( a b ) = μ ( a ) μ ( b ) ,其中gcd(a,b)=1;
2: d | n μ ( d ) = 0 , ( n > 1 )
3: d | n μ ( d ) d = φ ( n ) n

线性筛莫比乌斯函数
#define MAXN 1000000
int mu[MAXN],prim[MAXN],vis[MAXN],c;
void Solve()
{
    mu[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(vis[i]==0)
        {
            prim[c++]=i;
            mu[i]=-1;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            vis[i*prim[j]]=1;
            if(i%prim[j]==0)
            {
                mu[i*prim[j]]=0;
                break;
            }
            mu[i*prim[j]]=-mu[i];
        }
    }
}
莫比乌斯反演

形式一:
F ( n ) = d | n f ( d )
f ( n ) = d | n μ ( d ) F ( n d )
形式二:
F ( n ) = n | d f ( d )
f ( n ) = n | d μ ( d n ) F ( d )
一些问题 bzoj 3930 选数
1.求 1 a 1 b [ g c d ( x , y ) = 1 ]
f ( i ) = [ g c d ( x , y ) = i ] F ( i ) = [ i | g c d ( x , y ) ]
F ( i ) = [ a i ] [ b i ] = i | d f ( d )
f ( i ) = i | d μ ( d i ) F ( d )

逆元函数

模数为m:
a i n v [ a ] 1
i n v [ a ] = a p h i [ m ] 1

性质

1.(完全积性函数,不需要(a,b)=1)在模素数p的意义下:
i n v [ a b ] = i n v [ a ] i n v [ b ]
证明
在模素数p的意义下:
a i n v [ a ] 1 , b i n v [ b ] 1 a b i n v [ a ] i n v [ b ] 1
i n v [ a b ] = i n v [ a ] i n v [ b ]

线性筛逆元函数

Solution1:(P为素数)

int inv[MAXN],prim[MAXN],c,P;
void Solve()
{
    inv[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(inv[i]==0)
        {
            prim[c++]=i;
            inv[i]=PowMod(i,P-2);
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            inv[i*prim[j]]=inv[i]*inv[prim[j]];
            if(i%prim[j]==0)
                break;
        }
    }
}

Solution2:(P为素数)

扫描二维码关注公众号,回复: 3095789 查看本文章
void Solve()
{
    inv[1]=1;
    for(int i=2;i<P;i++)
        inv[i]=1LL*(P-P/i)*inv[P%i]%P;
}

证明:
i n v [ 1 ] = 1
假设当前已经求出 i n v [ 1 ] , i n v [ 2 ] , , i n v [ k 1 ] ,当前要求 i n v [ k ] .
P = [ P k ] k + P%k;
令 a=P%k ,有 a = P [ P k ] k ;
i n v [ a ] a i n v [ a ] ( P [ P k ] k ) i n v [ a ] ( [ P k ] k ) 1
i n v [ k ] = i n v [ a ] ( [ P k ] )

补充:求阶乘的逆元
void Solve()
{
    fac[0]=1;
    for(int i=1;i<=n;i++)
        fac[i]=1LL*fac[i-1]*i%P;
    inv[n]=PowMod(fac[n],P-2);
    for(int i=n-1;i>=0;i--)
        inv[i]=1LL*(i+1)*inv[i+1]%P; 
}

线性筛 g c d ( a , b ) , b 为定值

g [ i ] = g c d ( i , b ) , e k [ i ] = p 1 k 1 ,其中, i = p 1 k 1 p 2 k 2 p m k m ( p 1 < p 2 < < p m )

int g[MAXN],ek[MAXN],prim[MAXN],c,P,b;
void Solve()
{
    g[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(g[i]==0)
        {
            prim[c++]=i;
            g[i]=max((b%i==0)*i,1);
            ek[i]=i;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            if(i%prim[j]==0)
            {
                ek[i*prim[j]]=ek[i]*ek[prim[j]];
                if(b%(ek[i]*prim[j])==0) g[i*prim[j]]=g[i]*prim[j];
                else g[i*prim[j]]=g[i];
                break;
            }
            ek[i*prim[j]]=prim[j];
            g[i*prim[j]]=g[i]*g[prim[j]];
        }
    }
}

n 的正因子数目 d ( n )

n = p 1 k 1 p 2 k 2 p c k c ( p 1 < p 2 < < p c )
d ( n ) = i = 1 c ( k i + 1 )
e ( n ) = k 1

性质

1.(积性函数)
d ( a b ) = d ( a ) d ( b ) ,其中 g c d ( a , b ) = 1

线性筛 d ( n )
int d[MAXN],e[MAXN],prim[MAXN],c;
void Solve()
{
    g[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(d[i]==0)
        {
            prim[c++]=i;
            d[i]=2;
            e[i]=1;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            if(i%prim[j]==0)
            {
                d[i*prim[j]]=d[i]/(e[i]+1)*(e[i]+2);
                e[i*prim[j]]=e[i]+1;
                break;
            }
            d[i*prim[j]]=d[i]*d[prim[j]];
            e[i*prim[j]]=1;
        }
    }
}

n 的正因子之和 s ( n )

n = p 1 k 1 p 2 k 2 p c k c ( p 1 < p 2 < < p c )
s ( n ) = i = 1 c ( j = 0 k i p i j )

性质

1.(积性函数)
s ( a b ) = s ( a ) s ( b ) ,其中 g c d ( a , b ) = 1

线性筛 s ( n )

Solution1:
n = i p r i m [ j ] ,当 p r i m [ j ] i 的最小质因子时:
s ( n ) = ( i = 2 c ( j = 0 k i p i j ) ) ( j = 0 k 1 + 1 p 1 j ) = s ( i ) j = 0 k 1 + 1 p 1 j j = 0 k 1 p 1 j = s ( i ) p 1 k 1 + 2 1 p 1 k 1 + 1 1
p e ( i ) = p 1 k 1 + 1 , p e ( n ) = p 1 k 1 + 2
s ( n ) = s ( i ) p e ( n ) 1 p e ( i ) 1

LL s[MAXN],pe[MAXN];
int prim[MAXN],c;
void Solve()
{
    s[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(!s[i])
        {
            prim[c++]=i;
            s[i]=i+1;
            pe[i]=i*i;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            if(i%prim[j]==0)
            {
                pe[i*prim[j]]=pe[i]*prim[j];
                s[i*prim[j]]=s[i]/(pe[i]-1)*(pe[i*prim[j]]-1)
                break;
            }
            s[i*prim[j]]=s[i]*s[prim[j]];
            pe[i*prim[j]]=pe[prim[j]];
        }
    }
}

Solution 2:
n = i p r i m [ j ] ,当 p r i m [ j ] i 的最小质因子时:
s ( n ) = ( i = 2 c ( j = 0 k i p i j ) ) ( j = 0 k 1 + 1 p 1 j )
= ( i = 2 c ( j = 0 k i p i j ) ) ( j = 1 k 1 + 1 p 1 j + j = 0 k 1 p 1 j j = 1 k 1 p 1 j )
= ( i = 2 c ( j = 0 k i p i j ) ) ( p 1 j = 0 k 1 p 1 j + j = 0 k 1 p 1 j p 1 j = 0 k 1 1 p 1 j )
= s ( i ) ( p 1 + 1 ) s ( i p 1 ) p 1

LL s[MAXN];
int prim[MAXN],c;
void Solve()
{
    s[1]=1;
    for(int i=2;i<MAXN;i++)
    {
        if(s[i]==0)
        {
            prim[c++]=i;
            s[i]=i+1;
        }
        for(int j=0;1LL*prim[j]*i<MAXN;j++)
        {
            if(i%prim[j]==0)
            {
                s[i*prim[j]]=s[i]*(prim[j]+1)-s[i/prim[j]]*prim[j];
                break;
            }
            s[i*prim[j]]=s[i]*s[prim[j]];
        }
    }
}

补充题目

模板题
CQOI 3512 筛法求素数表
CQOI 3515 乘法逆元表
CQOI 2710 欧拉函数的值
POJ 2478 Farey Sequence
51Nod 1240 莫比乌斯函数
模板变式
HDU 3501 Calculation:利用欧拉函数性质3
POJ 3090 Visible Lattice Points
HDU 5317 RGCDQ

猜你喜欢

转载自blog.csdn.net/qq_41343943/article/details/82318004