初等数论c++

初等数论c++
初等数论c++

备注:纯手写代码,注释。

数论

1、素数

(1)暴力求解法

根据素数的概念,没有1和其本身没有其他正因数的数。所以只需枚举比这个数小的数,看能整除即可;

C++代码:

#include

#include

#include

using namespace std;

bool determine(int number)

{

if(n<=2)return false;

if(!n%2)return false;

for(int i=3;i<=ceil(sqrt(number));i+=2)

//去掉了偶数的判断,效率提高一倍

/*如果number整除以i,那么会得到两个的因数,

而较小的那个因数不会超过number的二分之一次方;

所以只需判断到number的平方根向上取整即可;*/

if(number%i);

else return false;

return true;

}

int main()

{

int sum;

cin>>sum;

if(determine(sum))

cout<<"YES!";

else cout<<"NO!";

return 0;

}

时间复杂度:o(sqrt(n)/2);

空间复杂度:几乎没有;

(2)一般线性筛法:

因为任何一个合数都能分解成几个素数相乘的形式;

所以可以做一个表,首先把2设为质数,然后将2的倍数设为合数,剩下的数就是新得到的质数,然后重复这个过程,直到筛到合

适的范围即可;

但是这个算法有缺陷:

1、同一个数可能被筛多次,这就产生了多余的步骤。

2、占用空间很大,如果使用bool数组的话,只能筛到1e9;

3、从1-n筛,不能从m-n开始筛;

C++代码:

#include

#include

#include

using namespace std;

bool s[1000000000];

int m,n;

int main()

{

cin>>m>>n;

memset(s,true,n);

s[0]=s[1]=0;

//输出M—N之间所有素数;

for(int i=2;i<=ceil(sqrt(n));++i)

if(s[i])

{

for(int j=i;j<=n;++j)

if(s[i*j])

s[i*j]=false;

}

for(int i=m;i<=n;++i)

if(s[i])

cout<

return 0;

}

时间复杂度:o(n*loglogn);

空间复杂度:很大!注意数据大的话可能会爆空间;

(3)线性筛法求素数

这个占空间就更大了,需要使用一个bool数组和int数组

而亲身试验得到int数组最多开到1e8……

很无语,快确实是快了,但是测试数据一大,爆空间就更容易了;#include

#include

#include

using namespace std;

int m,n,sum;

bool inp[1000000000];

int s[100000000]={0,0};

int main()

{

cin>>m>>n;

for(int i=2;i<=n;++i)

{

if(!inp[i])

s[sum++]=i;

for(int j=0;j

{

inp[i*s[j]]=true;

if(!(i*s[j]))

break;

}

}

for(int i=m;i<=n;++i)

if(!inp[i])

cout<

return 0;

}

2、唯一分解定理

任何数都可以被唯一的分解成多个素数之积例如:456=2*2*2*3*19;

C++代码:

#include

#include

#include

#include

#include

using namespace std;

bool s[1000000];

int m,n,sum=0,num;

int Prime[1212121];

int zhi[1500];

void Primes()

{

for(int i=1;i<=num;++i)

s[i]=true;

s[0]=s[1]=0;

for(int i=2;i<=num;++i)

if(s[i])

{

Prime[++sum]=i;

for(int j=i;j<=num;++j)

if(s[i*j])

s[i*j]=false;

}

}

int main()

{

int flag=0;

cin>>num;

int number=num;

Primes();

if(s[num])

{

cout<

return 0;

}

cout<

while(num>1)

for(int i=1;num>1&&i<=sum;++i) if(!(num%Prime[i]))

{

zhi[++flag]=Prime[i];

num/=Prime[i];

}

sort(zhi+1,zhi+flag+1);

cout<

for(int i=2;i<=flag;++i)

cout<<"*"<

return 0;

}

首先做一个质数表,并把质数存到数组里,然后用数模每个素数,如果为0则记录素数,最后排个序输出;

4、欧拉函数

欧拉函数φ(n)为不大于n的与n互素的数的个数;

A与B互素,表示a与b的最大公约数为1,即(a,b)=1;

欧拉函数的符号φ读作fhi,在搜狗的特殊符号里可以找到;

,其中pi为x的质因数,其中φ(1)=1(唯一与1互质的数是1本身)

设n为正整数,以φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值

φ:N→N,n→φ(n)称为欧拉函数。

几个性质(来自百度百科)

1、若n是质数p的k次幂,,因为除了p的倍数外,其他数都跟n互质。

2、欧拉函数是积性函数——若m,n互质,

3、特殊性质:当n为奇数时, , 证明与上述类似。

4、若n为质数则

5、设p是素数,a是一个正整数,那么

C++实现:

#include

#include

#include

#include

#include

using namespace std;

bool s[1000000];

int m,n,sum=0,num;

int Prime[1212121];

int zhi[1500];

bool asd[1500];

int phi(int n)

{

int i,rea=n;

for(i=2;i*i<=n;i++)

{

if(n%i==0)

{

rea=rea-rea/i;

while(n%i==0) n/=i;

}

}

if(n>1)

rea=rea-rea/n;

return rea;

}

void Primes()

{

for(int i=1;i<=num;++i)

s[i]=true;

s[0]=s[1]=0;

for(int i=2;i<=num;++i)

if(s[i])

{

Prime[++sum]=i;

for(int j=i;j<=num;++j)

if(s[i*j])

s[i*j]=false;

}

}

int main()

{

int flag=0;

cin>>num;

int number=num;

Primes();

if(num==1||!num)

{

cout<<"fhi"<<'('<

cout<

return 0;

}

if(s[num])

{

cout<<"fhi"<<'('<

return 0;

}

while(num>1)

for(int i=1;num>1&&i<=sum;++i)

if(!(num%Prime[i]))

{

zhi[++flag]=Prime[i];

num/=Prime[i];

}

int fenzi=1,fenmu=1;

sort(zhi+1,zhi+flag+1);

for(int i=1;i<=flag;++i)

if(!asd[zhi[i]])

{

asd[zhi[i]]=true;

fenzi*=zhi[i]-1;

fenmu*=zhi[i];

}

cout<<"fhi("<

//cout<<"fhi("<

/*这是另一种求欧拉函数值的方法*/

return 0;

}

5、欧几里得算法

辗转相除法,根据公式(a,b)=(b,r)

其中r为a%b,即a/b;

C++代码:

(1)递归

#include

#include

using namespace std;

int GCD(int a,int b)

{

if(a%b)

return GCD(b,a%b);

else return b;

}

int main()

{

int a,b;

cin>>a>>b;

cout<

return 0;

}

(2)递推

#include

using namespace std;

int main()

{

int a,b,r;

cin>>a>>b;

r=m%n;

while(r!=0)

{

a=b;

b=r;

r=m%n;

}

cout<

return 0;

}

6、扩展欧几里得

扩展欧几里得又称斐蜀定理,对于不完全为0 的非负整数a,b,gcd(a,b)表示a,b 的最大公约数,必然存在整数对x,y ,使得gcd(a,b)=ax+by;

求同余方程

#include

void exgcb(int a,int b,int &x,int &y)

{

if(!b)

{

x=1;y=0;

return;

int q=a/b;

int r=a%b;

exgcb(b,r,y,x);

y-=q*x;

}

int main()

{

int x,y;

int a,b;

scanf("%d %d",&a,&b);

exgcb(a,b,x,y);

while(x<0)

x+=b;

printf("%d",x);

return 0;

}

求乘法逆元

#include

void exgcb(int a,int b,int &x,int &y) {

if(!b)

x=1;y=0;

return;

}

int q=a/b;

int r=a%b;

exgcb(b,r,y,x);

y-=q*x;

}

int Multiplicative inverse(int a,int b) {

int x,y;

int gcb=GCD(a,b,x,y);

if(1%gcb)return -1;

x*=1%gcb;

b=abs(b);

int answer=x%b;

while(answer<=0)

answer+=b;

return answer;

}

int main()

{

int x,y;

int a,b;

scanf("%d %d",&a,&b);

exgcb(a,b,x,y);

while(x<0)

x+=b;

printf("%d\n",x);

cout<

return 0;

}

求线性方程ax+by=c

这个方程等同于ax≡c(mod b)

所以

(此文档部分内容来源于网络,如有侵权请告知删除,文档可自行编辑修改内容,供参考,

感谢您的配合和支持)

相关主题
相关文档
最新文档