数论部分知识

Posted wxyww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论部分知识相关的知识,希望对你有一定的参考价值。

费马定理:

ap≡a(mod p)

其中p为质数,且a不是p的倍数

证明:

。。。。。

 

欧拉定理:

aφ(p)≡1(mod p)

φ(x)(欧拉函数)为小于等于x且与x互质的数的个数

φ(x)=∏(pi-1)*piki-1  其中pi表示 x的质因数,ki表示这种质因数的个数

特别的对于质数  φ(x)=x-1。

欧拉函数的代码实现:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int ol(int x)
 5 {
 6     int ans=1;
 7     for(int i=2;i*i<=x;++i)
 8     {
 9         if(x%i==0)
10         {
11             x/=i;
12             ans*=i-1;
13         }
14         while(x%i==0)
15         {
16             x/=i;
17             ans*=i;
18         }
19     }
20     if(x>1) ans*=x-1;
21     return ans;
22 }
23 int main()
24 {
25     int a;
26     scanf("%d",&a);
27     printf("%d",ol(a));
28     return 0;
29 }

最后函数里那个如果x>1,ans*=x-1一开始让我很懵,后来一想,如果这个数将所有的质因数除过一遍之后,剩下的数如果不是1,那么剩下的肯定只有一个并且是个质数(证明很显然)

 

 

 筛法

有两种筛法,第一种叫做埃拉托斯特尼筛法(复杂度O(n log logn)),另一种是欧拉筛法(复杂度O(n))

埃拉托斯特尼筛法其实就是用已得到质数,去将他的所有n以内倍数标记为合数,最后剩下的就是合数。

在进行筛法的同时,可以顺便找到每个数的最小质因数(就是第一次更新他的那个质数)

 

欧拉筛法:在埃氏筛法中每一个合数可能会被更新很多遍,这些是没有必要的,所以就有了欧拉筛。

欧拉筛的思路就是保证每个合数只被他的最小质因数筛掉。用一个数组dis来存已经得到的素数,

然后再用已经得到素数取筛其他的数,主要的地方是代码中  if(i%dis[j]==0) break;  这个地方。

两个筛法的代码

 

 1 #include<cstdio>
 2 #include<iostream>
 3 
 4 using namespace std;
 5 const int N=10000;
 6 void aa(int n);
 7 void ol(int n);
 8 int main()
 9 {
10     int n;
11     scanf("%d",&n);
12     aa(n);
13     printf("\n");
14     ol(n);
15 }
16 
17 void aa(int n)//埃氏筛法 
18 {
19     int vis[N];
20     int dis[N];//用来存最小质因数 
21     for(int i=2;i<=n;++i)
22     {
23         if(!vis[i])
24         {
25             for(int j=i*2;j<=n;j+=i)
26             {
27                 if(!vis[j])
28                 {
29                     vis[j]=1;
30                     dis[j]=i;
31                 }
32             }
33         }
34     }
35     for(int i=1;i<=n;++i)
36     {
37         if(!vis[i])
38         {
39             printf("%d ",i);
40         }
41     }
42 }
43 void ol(int n)
44 {
45     int vis[N];
46     int dis[N],js=0;
47     for(int i=2;i<=n;++i)
48     {
49         if(!vis[i])
50         {
51             dis[++js]=i;
52         }
53         for(int j=1;dis[j]*i<=n;++j)
54         {
55             vis[i*dis[j]]=1;
56             if(i%dis[j]==0) break;
57         }
58     }
59     for(int i=1;i<=n;++i)
60     {
61         if(!vis[i]) printf("%d ",i);
62     }
63 }

 

 快速幂与快速乘法

 尽管快速幂与快速乘法好像扯不上什么关系,但是东西不是很多,就一起整理到这里吧

快速幂思想就是将ax看作x个a相乘,用now记录当前答案,然后将指数每次除以2,然后将当前答案平方,如果x的2进制最后一位为1的话,就将答案乘以现在的数。快速乘法类似,只是将a*x看作x个a相加。

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int mi(int a,int x)
 5 {
 6     int ans=1;
 7     for(int now=a;x>=1;x>>=1,now=now*now)//a表示底数,x表示次数 
 8     {
 9         if(x&1) ans=ans*now;
10      } 
11      return ans;
12 }
13 int cheng(int a,int x)//表示a*x 
14 {
15     int ans=0;
16     for(int now=a;x>=1;now=now*2,x>>=1)
17     {
18         if(x&1) ans=ans+now;
19     }
20     return ans;
21 }
22 int main()
23 {
24     int a,x;
25     scanf("%d%d",&a,&x);
26     printf("快速幂 %d\n",mi(a,x));
27     printf("快速乘法 %d\n",cheng(a,x));
28     return 0;
29 }

 

以上是关于数论部分知识的主要内容,如果未能解决你的问题,请参考以下文章

PAT 数列的片段和简单数论

数论知识整理

专题数论

常用初等数论小知识

数论部分第一节:素数与素性测试详解

小升初数学数论知识归纳总结