概述
质数
定义: 不讲了qwq...
性质: 对于一个足够大的整数N,不超过N的质数大约有(N lnN) 个.
试除法:
*若一个正整数N为合数,则存在一个能整除N的数T,其中(2≤T≤sqrt{N})
inline bool int prime(int n)
{
for(RN i=2;i<=sqrt(n);i++)
{
if(n%i==0)
return false;
}
return true;
}
Miller-Robbin:
1.问题描述:
*测试一个正整数 p 是否为素数,需要较快且准确的测试方法。((p≤10^{18}))
费马小定理:
对于质数 p 和任意整数 a ,有 (a^p≡a(mod p)) 。
反之,若满足 (a^p≡a(mod p)),p 也有很大概率为质数。
将两边同时约去一个 a ,则有 (a^p−1≡1(mod p)) 。
也即是说:假设我们要测试 n 是否为质数。我们可以随机选取一个数 a ,然后计算 (a^n−1(mod n)) ,如果结果不为 1 ,我们可以 100% 断定 n 不是质数。否则我们再随机选取一个新的数 a 进行测试。如此反复多次,如果每次结果都是 1 ,我们就假定 n 是质数.
二次探测定理:
如果 p 是奇素数,则 (k^2≡1(mod p)) 的解为 k≡1 或 (k≡p−1(mod p))
即如果当我们用一个a费马小n后,看n是不是偶数,如果是,则取(dfrac{n}{2}),根据二次探测定理可知,(dfrac{n}{2})即为k,则再判断(n^2≡p−1(mod p))或(n^2≡1(mod p))是否正确.若不成立,则不是质数.如果n是奇数,则直接跳过二次探测定理,用下一个a来费马.
几个 ai 的值: 2,3,5,7,11,61,13,17。用了这几个 ai,就连那个被称为强伪素数的 46856248255981 都能被除去.
单次测试失败的几率为 (dfrac{1}{4}) 。那么假设我们做了 times 次测试,那么我们总错误的几率为 ((dfrac{1}{4})^{time})如果 times 为 20 次,那么错误概率约为 0.00000000000090949470 也就是意味着不可能发生的事件。
单次时间复杂度是 O(logn) ,总复杂度就是 O(times(log{n})) 了。注意 long long 会爆,用 int128 就行了。
代码实现:
#define ll long long
ll p,a[]={2,3,5,7,11,61,13,17};
inline ll mul(ll a,ll b,ll mod)
{
ll ans=0;
for(ll i=b;i;i>>=1)
{
if(i&1) ans=(ans+a)%p;
a=(a<<1)%p;
}
return ans%p;
}
inline ll Pow(ll a,ll b,ll p)
{
ll ans=1;
for(ll i=b;i;i>>=1)
{
if(i&1) ans=mul(ans,a,p);
a=mul(a,a,p);
}
return ans%p;
}
inline bool Miller_Robbin(ll p)
{
if(p==2) return true;
if(p==1 || !(p%2)) return false;
ll d=p-1;int s=0;
while(!(d&1)) d>>=1,++s;
for(int i=0;i<=8 && a[i]<p;++i)
{
ll x=Pow(a[i],d,p),y=0;
for(int j=0;j<s;++j)
{
y=mul(x,x,p);
if(y==1 && x!=1 && x!=(p-1)) return false;
x=y;
}
if(y!=1) return false;
}
return true;
}
Pollard-Rho 大合数分解:
算法流程:
先判断当前数N是否是素数(Miller_Rabin)了,如果是则直接返回。如果不是素数的话,试图找到当前数的一个因子(可以不是质因子)。然后递归对该因子和约去这个因子的另一个因子进行分解。
算法解决:
那么,如何找到这个数的一个因子呢?对于一个大整数n,采用一种随机化算法,我们取任意一个数x使得x是n的质因数的几率很小,但如果取两个数x1以及x2使得它们的差是n的因数的几率就提高了.理论支撑:
生日悖论:
假设一年有 N 天,那么只要 $n≥sqrt{N} $存在相同生日的概率就已经大于 50% 了.即假如一个班级有58位同学,那么必定有两个同学的出生日期是相同的.正确性证明
利用伪随机数判断:
根据生日悖论,我们可以生成很多随机数相减法,与要求的N找最大公约数, 假设枚举的两个数为 i,j ,假设 i>j ,那么判断一下 gcd(i−j,n) 是多少,如果非 1 ,那么我们就已经找出了一个 n 的因子了,这样的概率随着枚举的组数变多会越来越大。但如果我们一开始就把所有的随机数都造出来,不仅内存储存不下,而且效率也不高,所以就有了以下生成伪随机函数:
f(x)=(x2+a)modn
inline int find_factorplus(int N) {
a = 2;
b = a;
do {
a = f(a);//a runs once
b = f(f(b));//b runs twice as fast
p = GCD( abs( b - a ) , N);
if( p > 1 ) return p;//Found factor: p
} while( b != a );
return 0;//Failed.
}
一开始只需要两个数a,b,而且a可以rand也可以自己取(例如2),b可以根据随机函数生成.然而一般这种简单的随机数都会出现循环节,我们需要判断一下循环节.
Floyd判环:
两个人同时在一个环形跑道上起跑,如果一个人是另外一个人的两倍速度,那么这个人绝对会追上另外一个人。追上时,意味着其中一个人已经跑了一圈了。
根据上面的结论,我们可以把b变成2倍速度a,如果发现有环,即a==b,那么跳出循环.寻找另外一个a.
inline int find_factorplus(int N) {
a = 2;
b = a;
do {
a = f(a);//a runs once
b = f(f(b));//b runs twice as fast
p = GCD( abs( b - a ) , N);
if( p > 1 ) return p;//Found factor: p
} while( b != a );
return 0;//Failed.
}
Miller-Rabin 优化:
这个算法对于因子多,因子值小的数 n 是较为优异的。
也就是对于它的一个小因子 p , Pollard−Rho 期望在 O((sqrt{p})) 时间内找出来。
但对于 n 是一个质数的情况,就没有什么较好的方法快速判断了,那么复杂度就是 O((sqrt{p})) 的。
此时就退化成暴力试除法了。
此时我们考虑用前面学习的 Miller−Rabin 算法来优化这个过程就行了。
代码实现:
#include<bits/stdc++.h>
using namespace std;
#define RI register int
#define LL long long
inline LL read()
{
LL res=0,f=1;
char ch=getchar();
while(ch!='-'&&(ch>'9'||ch<'0'))
ch=getchar();
if(ch=='-')
f=-1,ch=getchar();
while(ch>='0'&&ch<='9')
res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
return res*f;
}
LL ans;
LL ksm(int x,LL p,LL Mod)
{
if(p==1)
return x%Mod;
LL res=ksm(x,p>>1,Mod);
res=(__int128)res*res%Mod;
if(p&1)
res=(__int128)res*x%Mod;
return res%Mod;
}
LL gcd(LL x,LL y)
{
return y?gcd(y,x%y):x;
}
inline bool mr0(int x,LL p)
{
if(ksm(x,p-1,p)!=1)
return false;
LL k=p-1;
while(!(k%2))
{
k>>=1;
LL t=(ksm(x,k,p)+p)%p;
if(t!=1&&t!=p-1)
return false;
if(t==p-1)
return true;
}
return true;
}
inline bool mr(LL x)
{
if(x==46856248255981||x<2)
return false;
if(x==2||x==3||x==7||x==61||x==24251)
return true;
return mr0(2,x)&&mr0(3,x)&&mr0(7,x)&&mr0(61,x)&&mr0(24251,x);
}
inline LL find(LL x)
{
LL t1=rand()%x,c=rand()%x,t2=((__int128)t1*t1+c)%x;;
LL dif=abs(t1-t2),cnt=0;
__int128 G=gcd(dif,x);
if(G>1)
return G;
while(true)
{
t1=((__int128)t1*t1+c)%x;
t2=((__int128)t2*t2+c)%x;
t2=((__int128)t2*t2+c)%x;
if(t1==t2)
return gcd(G,x);
dif=abs(t1-t2);
if(G*dif%x==0)
return gcd(G,x);
G=G*dif%x;
if(cnt%127==0)
{
LL r=gcd(G,x);
if(r>1)
return r;
cnt=1;
}
cnt++;
}
}
inline void PollardRho(LL x)
{
if(x==1||x<ans)
return;
if(mr(x))
{
if(x>ans)
ans=x;
return;
}
LL y=x;
while(y==x)
y=find(x);
PollardRho(y);
PollardRho(x/y);
}
int main()
{
srand((unsigned)time(NULL));
int T=read();
while(T--)
{
LL x=read();
ans=1;
if(mr(x))
{
printf("Primen");
continue;
}
PollardRho(x);
printf("%lldn",ans);
}
return 0;
}
参考博客
质数的筛选:
给定一个整数N,求出1~N之间的所有质数.
Eratosthenes 筛法:
任意整数x的倍数都不是质数.
时间复杂度O((NloglogN))
inline void prime(int x)
{
memset(v,o,sizeof(v));
for(RN i=1;i<=n;i++)
{
if(v[i]) continue;
cout<<i<<endl;
for(RN j=i;j<=n/i;j++)
v[i*j]=1;
}
}
线性筛法:
从大到下累计质因子,让每一个数只有一种质因子产生方式
设数组V[]记录每个数的最小质因子.
1.依次考虑2~N之间每一个数i.
2.若v[i]=i,说明i是质数,把它保存下来.
3.扫描不大于v[i]的每个质数P,令v[i∗p]=p.也就是说在i的基础上累计一个质因子P,因为(pleqslant v[i]),所以p便是(p*i)的最小质因子.这样便能找出每一个数唯一的质因数分解方式.
时间复杂度O(N).
代码实现:
int v[maxn],prime[maxn];
inline void find(int n)
{
memset(v,0,sizeof(v));
for(RN i=2;i<=n;i++)
{
if(v[i])
continue;
cout<<i<<endl;
for(RN j=i;j<=n/i;j++)
v[i*j]=1;
}
}
质因数分解:
基本定理:
任何一个大于1的正整数都能唯一分解为有限个质数的乘积.
(color{BlueViolet}{N=P_{1}^{c_{1}}*P_{22}^{c_{2}}*...P_{m}^{c_{m}}})
其中(c_{i})都是正整数,(p_{i})都是质数,且满足(p_{1}<p_{2}<...<p{m}).
方法1 试除法:
inline void find(int n)
{
memset(c,0,sizeof(c));
m=0;
for(RN i=2;i*i<=n;i++)
{
if(n%i==0)
{
p[++m]=i;
while(n%i==0)
n/=i,c[m]++;
}
}
if(n>1)
{
p[++m]=n;
c[m]=1;
}
for(RN i=1;i<=m;i++)
{
cout<<p[i]<<"^"<<c[i]<<endl;
}
}
方法2 Pollard-Rho
详情见上.
约数
约数,又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a。a称为b的倍数,b称为a的约数。记为(b|a).
算数基本定理的推论:
已知(color{BlueViolet}{N=P_{1}^{c_{1}}*P_{22}^{c_{2}}*...P_{m}^{c_{m}}})(({P_{1}<P_{2}<P_{3}<...<P_{m}}))
N的正约数个数为 ((c_1+1)*(c_2+1)*(c_3+1)*...*(c_m+1)=prodlimits_{i=1}^m(c_i+1))
N的所有正约数之和为 ((1+p_1+p_1^{2}+...+p_1^{c_1})*...*(1+p_m+p_m^{2}+...+p_m^{c_m}=prodlimits_{i=1}^m(sum_{j=0}^{c_i}(p_i)^j))
试除法——求N的正约数集合:
int f[1600],m=0;
for(RN i=1;i*i<=n;i++)
{
if(n%i==0)
{
f[++m]=i;
if(i!=n/i) f[++m]=n/i;
}
}
时间复杂度为O( (sqrt{N}))
(color{BlueViolet}{试除法推论}):
一个整数N的约数个数上界为(2sqrt{N}).
倍数法——求出1~N每个数的正约数集合:
inline void find(int n)
{
vector<int> f[50010];
for(RN i=1;i<=n;i++)
for(RN j=1;j<=n/i;j++)
{
f[i*j].push_back(i);
}
for(RN i=1;i<=n;i++)
{
int x=f[i].size();
for(RN j=0;j<x;j++)
printf("%d ", f[i][j]);
puts(" ");
}
}
时间复杂度O((Nlog{N})).
(color{BlueViolet}{倍数法推论}):
1~N的约数个数的总和大约为为(Nlog{N}).
最大公约数:
定义:最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。a,b的最大公约数记为gcd(a,b),同样的,a,b,c的最大公约数记为gcd(a,b,c),多个整数的最大公约数也有同样的记号。求最大公约数有多种方法,常见的有质因数分解法、短除法、辗转相除法、更相减损法。与最大公约数相对应的概念是最小公倍数,a,b的最小公倍数记为lcm[a,b].
定理:
(forall a,bsubset{N},gcd(a,b)*lcm(a,b)=a*b).
求法:
更相减损术 :
(forall a,bsubset{N},有 gcd(a,b)=gcd(b,a-b)=gcd(a,a-b))
(forall a,bsubset{N},有 gcd(2a,2b)=2gcd(a,b))
(color{DeepPink}{text{适用于高精度算法}})
欧几里得算法 :
(forall a,bsubset{N},bneq 0, gcd(a,b)=gcd(b,a mod b))
inline int gcd(int a,int b)
{
return b? gcd(a,a%b):a;
}
时间复杂度O((log(a+b)))
互质与欧拉函数
定义:
(forall a,b,subset{N},若 gcd(a,b)=1,则称a,b互质.)
(若gcd(a,b)=gcd(b,c)=gcd(a,c)=1,则称a,b,c两两互质.)
欧拉函数:
1~N中于N互质的数的个数被称为欧拉函数,记为(varphi(N))
(varphi(N)=N*prodlimits_{(prime)P|N}(1-frac{1}{p}))
根据计算公式,可以在分解质因数的时候求出欧拉函数.
int get_phi(int x){
int re=x;
for(int i=2;i*i<=x;i++)
if(x%i==0){
re/=i;re*=i-1;
while(x%i==0)
x/=i;
}
if(x>1) re/=x,re*=x-1;//最后一个.
return re;
}
时间复杂度O((sqrt{N})).
欧拉函数性质:
((1).forall n>1 ,1sim n) 中与n互质的数的和为 (ntimesfrac{varphi(n)}{2}.)
((2).)若a,b互质,则(varphi(ab)=varphi(a)timesvarphi(b).)
((3).)当(n)为奇数时,(varphi(2n)=varphi(n).)
((4).)若(pmid n),且(p^2mid n),则(varphi(n)=varphi(frac{n}{p})times p.)
((5).)若(pmid n),且(p^2nmid n),则(varphi(n)=varphi(frac{n}{p})times (p-1).)
((6).)若p为质数,则(varphi(p)=p-1.)
((7).)$sum_{dmid n}varphi(d)=n $
由此我们便可以通过线性筛在O(n)的时间内算出(2sim N)中每一个数的欧拉函数.
inline void find(int n)
{
memset(v,0,sizeof(v));
int m=0;
for(RN i=2;i<=n;i++)
{
if(!v[i])
{
v[i]=i,p[++m]=i;
phi[i]=i-1;
}
for(RN j=1;j<=m;j++)
{
if(p[j]>v[i]||p[j]>n/i)
break;
v[i*p[j]]=p[j];
phi[i*p[j]]=phi[i]*(i%p[j] ? p[j]-1 : p[j]);
}
}
}
以及Eratosthenes筛法:
inline void find(int n)
{
for(RN i=2;i<=n;i++)
phi[i]=i;
for(RN i=2;i<=n;i++)
if(phi[i]==i)
for(int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
}
时间复杂度O((N log{N}))
概率与数学期望
样本点:随机实验的某种可能结果.
样本空间:所有可能结果所形成的集合.
随机事件:
随机变量:
概率:
定义:
博弈论:
NIM博弈
局面:游戏中面临的状态.
先手:整局游戏第一个行动的人.
后手:整局游戏第二个行动的人.
必败局面:若在某一局面下无论采取何种行动, 都会输掉游戏的局面.
必胜局面/最优策略:若在某一局面存在某种行动,使行动后对手面临必败局面.
NIM不存在平局,只有先手必胜和先手必败的两种情况.
定理:
NIM博弈先手必胜,当且仅当(A_1xorA_2xorA_3xor...xorA_n≠0)
转载于:https://www.cnblogs.com/lvhuanzhu/p/10902033.html
最后
以上就是甜美鲜花为你收集整理的数论质数约数概率与数学期望博弈论:的全部内容,希望文章能够帮你解决数论质数约数概率与数学期望博弈论:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复