先拜大牛。感谢贾志鹏严谨的思维。以及简单清晰的论文描述。

一定要结合论文看。我只是提出我觉得关键的部分。论文在网上随处可见。贾志鹏线性筛。

 

开头两种线性筛的比较。

一种是传统的线性筛。时间复杂度为N*log(log(N))。

另外一种是优化了合数的筛法。文中称作Euler线性筛。

其优化的地方。

举个例子:合数6。 是2的倍数也是3的倍数。 当你用传统的筛法的时候在遍历2的倍数的时候会遍历到6。遍历3的倍数的时候同样也会遍历到6。

而另外一种只会筛出6为2的倍数。3就不会筛6了。

另外个人认为筛法二有一个很重要的思想。当i为合数的时候。其实脑海里不认为是合数。而是素数的乘积。这样就能比较直观地确定这个算法的正确性了。

 

积性函数。

分为完全积性和条件积性。

我们最喜欢的积性。大概就是互素积性了。因为满足互素积性的话。根据算术基本定理。就能够简单做到推广到任意实数。

f(1) = 1 。 这个在我们高中数学题。抽象函数。就已经能简单知道了。

 

欧拉函数。就不再谈了。包括其线性筛的那一步至关重要的证明。也在我其它博文提到过了。

其 欧拉定理和费马小定理的作用。我得再多补充一点。

以及互质数和。 n的互质数和为 n*φ(n)/2.

 

莫比乌斯函数和容斥定理的关系。

可以发现莫比乌斯函数其实就是容斥定理的映射一般。

莫比乌斯函数 是我们再熟悉不过的了。不熟悉可以看这里

首先看 (-1)^r m = p1p2p3p4p5pr 其实就是在模拟容斥定理。

假如一但不是素数。那就为0.

 

两个函数的线性筛。这其实是我们处理问题的基本。这里需要讲的是。不一定只有积性函数才可以用这种筛法。

只要你能找到f(kn) n整除k 和不整除的两个时刻所对应的递推式。这个在扩展问题中会出现。

问题一:求1~N对质数P的乘法逆元。

关于f(n)为完全积性函数。根据同余定理可以简单获得。要证明的话。减法证同余即可。

P = nt + k

n'  ≡ n*(t^2)*f(k)^2 (mod P)

这个证明过程很漂亮(很佩服这么顺畅,思维这么清晰)。也是根据同余定理。还有逆元的性质。就能推理的。

这个问题的意义。可以求N!的 mod P 的逆元了。逆元还是很有用的。因为毕竟除法并没有特别好的同余式。(依稀还记得那两个。)

问题二:给T组N,M.依次求出读贾志鹏线性筛有感 (莫比乌斯函数的应用)的值.(N,M<=10^6,T<=10^3)

求解gcd(a,b).把gcd(a,b)当做n.再通过欧拉函数和式。推导过程如下。

读贾志鹏线性筛有感 (莫比乌斯函数的应用)

第二个等式是用d来看待式子的方法来化简和式的。

之后再穷举d即可。

 

 

#include<stdio.h>
#include<string.h>
#define    N 100

bool mark[N+5];
int prime[N+5];
int num;
int euler[N+5];
int Min(int a,int b){return a>b?a:b;}
void Euler()
{
    int i,j;
    num = 0;
    memset(euler,0,sizeof(euler));
    memset(prime,0,sizeof(prime));
    memset(mark,0,sizeof(mark));
    euler[1] = 1; // multiply function
    for(i=2;i<=N;i++)
    {
        if(!mark[i])
        {    
            prime[num++] = i;
            euler[i] = i-1;
        }
        for(j=0;j<num;j++)
        {
            if(i*prime[j]>N){break;}
            mark[i*prime[j]] = 1;
            if(i%prime[j]==0)
            {
                euler[i*prime[j]] = euler[i]*prime[j];
                break;
            }
            else
            {
                euler[i*prime[j]] = euler[prime[j]]*euler[i];
            }
        }
    }
}

int main()
{
    int i;
    int M1,M2;
    Euler();
    for(i=0;i<num;i++)printf("%d ",prime[i]);
    printf("\n");
    for(i=1;i<=N;i++)printf("%d ",euler[i]);
    printf("\n");
    M1 = 2;
    M2 = 3;
    int sum = 0;
    int min = Min(M1,M2);
    for(i=1;i<=min;i++)
    {
        sum += euler[i]*(M1/i)*(M2/i);
    }
    printf("%d\n",sum);
}
the second problem test

相关文章:

  • 2021-06-21
  • 2022-12-23
  • 2021-11-04
  • 2022-02-17
  • 2021-12-08
  • 2021-12-21
  • 2021-09-10
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-06-13
  • 2022-12-23
  • 2021-06-22
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案