枚举因子法
bool judge(int n)
{
if(n==1) return false;
for(int i=2;i*i<=n;i++)
{
if(n%i==0) return false;
}
return true;
}
要把1特判掉。 可以1秒内单次判断1~10^16以内的任意一个素数是否是素数
素数筛:提前处理1~N的全体素数,后可以直接判断是否是素数
const int N=1000001;
bool notprime[N];
void init()
{
notprime[1]=1;
for(int i=2;i<N;i++)
{
if(notprime[i]==false)
{
for(int j=i+1;j<N;j=j+i)
{
notprime[j]=true;
}
}
}
}
mertens定理
https://wenku.baidu.com/view/c167c17931b765ce05081473.html看一波,嗯,这种东西看不懂还是要看的,不求甚解
可以一秒内10^7以内的质数和合数分离开来,接下来让每个合数只删除一次
欧拉筛(线性筛)每一个素数只被记录一次,每一个合数只会被一个唯一的最小素因子标记一次。
https://wenku.baidu.com/view/4881881daaea998fcc220e99.html 原理还是可以看一下的
大致上讲:每一个数有唯一的最大因子,被唯一筛去,唯一最大因子*小于等于最小质因子就是对应的合数,且筛全了
用了反证。
const int N=1000001;
bool notprime[N];
int prime[N];
int pn;
void init()
{
pn=0;
notprime[1]=1;
for(int i=2;i<N;i++)
{
for(notprime[i]==false)
{
prime[pn++]=i;
}
for(int j=0;j<pn;j++)
{
notprime[prime[j]*i]==true;
if(i%prime[j]==0) break;
}
}
}
1秒钟处理从10^7~10^8
#include<algorithm>里面有__gcd函数,注意要会用
最大公约数:
设两数为a、b(a>b),用
表示a,b的最大公约数,r=a (mod b) 为a除以b的余数,k为a除以b的商,即
。辗转相除法即是要证明
。
第一步:令
,则设
第二步:根据前提可知
第三步:根据第二步结果可知,
也是
的因数
第四步:可以断定
与
,则
,则
,则a与b的一个公约数
,故c非a与b的最大公约数,与前面结论矛盾,因此c也是b与r的最大公约数)从而可知
,继而
。
证毕
注:以上步骤的操作是建立在刚开始时
的基础之上的,即m与n亦互质。
百度上的解释,海星,不用想了。
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
多个数求最大公约数
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int multi_gcd(int a[],int n)
{
int res=gcd(a[0],a[1]);
for(int i=2;i<n;i++)
res=gcd(res,a[i]);
return res;
}
最小公倍数略。
扩展欧几里得算法:
把这个实现和Gcd的递归实现相比,发现多了下面的x,y赋值过程,这就是扩展欧几里德算法的精髓。
可以这样思考:
对于a'=b,b'=a%b 而言,我们求得 x, y使得 a'x+b'y=Gcd(a',b')
由于b'=a%b=a-a/b*b (注:这里的/是程序设计语言中的除法)
那么可以得到:
a'x+b'y=Gcd(a',b') ===>
bx+(a - a / b * b)y = Gcd(a', b') = Gcd(a, b) ===>
ay +b(x - a / b*y) = Gcd(a, b)
因此对于a和b而言,他们的相对应的p,q分别是 y和(x-a/b*y)
使用扩展欧几里德算法解决不定方程的办法
对于不定整数方程pa+qb=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解。
有种较为不严谨的方法证明,不过至少弥补了一点空白,望某些数论大师补充修改:
由于我们知道,存在一组x与y使得a*x+b*y=gcd(a,b)。
将等式两边同时乘以整数k,即a*x*k+b*y*k=gcd(a,b)*k。如果c mod gcd(a,b)=f,则0<=f<gcd(a,b)。
那么可以令c=gcd(a,b)*k+f。这样一来,就有a*x*k+b*y*k+f=c。
若f
0,由于f<gcd(a,b)<=a<=b(假设a<=b),所以不存在f=a*m(m为整数),也就不存在a*(x*k+m)+b*y*k=c。也就是说,不存在a*x+b*y=c的整数解x与y。
所以f=0,即只有当c mod gcd(a,b)=0时,a*x+b*y=c有正整数解。得证。
上面已经列出找一个整数解的方法,在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后,p * a+q * b = Gcd(a, b)的其他整数解满足:
p = p0 + b/Gcd(a, b) * t
q = q0 - a/Gcd(a, b) * t(其中t为任意整数)
至于pa+qb=c的整数解,只需将p * a+q * b = Gcd(a, b)的每个解乘上 c/Gcd(a, b) 即可,但是所得解并不是该方程的所有解,找其所有解的方法如下:
在找到p * a+q * b = Gcd(a, b)的一组解p0,q0后,可以
得到p * a+q * b = c的一组解p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b)),p * a+q * b = c的其他整数解满足:
p = p1 + b/Gcd(a, b) * t
q = q1 - a/Gcd(a, b) * t(其中t为任意整数)
p 、q就是p * a+q * b = c的所有整数解。
上面是百度上的https://baike.baidu.com/item/扩展欧几里德算法/1053275?fr=aladdin比较透彻
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return d;
}
线性同余方程,求逆元
int solve(int a,int b,int n)
{
int d=gcd(a,n);
if(b%d==0) return -1;
int k=b/d;
int x,y;
exgcd(a,n,x,y);
return x*k;
}
分解质因数
算术基本定理https://baike.baidu.com/item/算术基本定理/10920095?fr=aladdin
这个写的通俗易懂,不错。
预处理素数筛
int p[100];
int e[100];
int cnt;
int fenjie(int n)
{
cnt=0;
for(int i=0;i<pn&&prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
p[cnt]=prime[i];
while(n%prime[i]==0)
n/=prime[i];
e[cnt]++;
cnt++;
}
if(n>1) p[cnt]=n;
e[cnt++]=1;
}
}
快速幂
long long pow_mod(long long a,long long n,long long m)
{
long long res=1;
while(n>0)
{
if(n%2==1) res=res*a%m;
a=a*a%m;
n/=2;
}
return res;
}
费马小定理
模素数是有循环节的,P-1
int getphi(int n)
{
int ans=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
ans-=ans/i;
while(n%i==0)
n/=i;
}
}
if(n>1) ans-=ans/n;
return ans;
}
https://baike.baidu.com/item/欧拉函数
baby step giant stephttps://www.cnblogs.com/wondove/p/7976525.html
不行了,看看其他人博客吧