一、余数基本公式:
二、一些模板
求a,b最大公约数:
int gcd(int a,int b)
{
if(b==0)return a;
gcd(b,a%b);
}
求a,b最小公倍数:
int lcm(int a,int b) return a*b/gcd(a,b);
快速幂:
void kuai(int b,int p,int k)
{
daan=1;
while(p!=0)
{
if(p%2!=0)daan=(daan*b)%k;
p=p/2;b=(b*b)%k;
}
}
高精加:
// daoxu // 存到a
void gjj(int a[],int b[])
{
if(a[0]<b[0]){a[0]=b[0];}
int jinwei=0,linshi;
for(int uu=1;uu<=a[0];uu++)
{
linshi=a[uu]+b[uu]+jinwei;
a[uu]=linshi%10;
jinwei=linshi/10;
}
if(jinwei>=1)
{
++a[0];
a[a[0]]=jinwei;
}
}
高精乘:
// daoxu //存到c[]
void gjc(int a[],int b[])
{
c[0]=a[0]+b[0]+5;
int jinwei=0,qidian,linshi;
for(int uu=1;uu<=a[0];uu++)
{
jinwei=0;
for(int vv=1;vv<=b[0];vv++)
{
linshi=c[vv+uu-1]+jinwei+a[uu]*b[vv];
c[vv+uu-1]=linshi%10;
jinwei=linshi/10;
}
if(jinwei>0)
{
c[uu+b[0]]=jinwei;
}
}
while(c[c[0]]==0)--c[0];
}
欧拉筛(因为每个合数都可表示为素数的积):
//然后利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
int main()
{
n=10000000;
for(i=2;i<n;i++)
{
if(!shi[i])
sushu[tot++]=i;
for(int j=0;j<tot&&i*sushu[j]<n;j++)
{
shi[i*sushu[j]]=1;
}
}
}
分解质因数:
cin>>n;
for(i=2;i<=n;i++)
{
while(!n%i)
if(n%i==0)
{
n=n/i;
cout<<i<<" ";
}
}
三、数论
欧几里得定理:
gcd(a,b)=gcd(b,a%b);
反证法+分类讨论 证明(需要一定逻辑觉悟):::
设gcd(a,b)=d,p、q互质,a=d*p、b=q*d;;;(a>b)
因为众所周知,余数=被除数-商*除数;;;
∴a%b=a-(a除以b的商)*b
即 a%b=dp-(dp/qd)*qd;;
∴a%b=d(p-(p/q)*q);;;←至于为什么这样导,实际上是为了分类讨论、、、、
注:因为余数大于等于0,p=后面的式子+余数,,所以p大于后面的数
情况一: p=(p除以q的商)*q 即p被q整除,所以a也被b整除;;;
所以a % b=p(p-p)=0;;
所以 gcd(b,a%b)=gcd(b,0)=b=gcd(a,b) ps:任何数和0的最大公约数是这个数本身,,,
情况二: p>(p除以q的商)*q
//如果gcd ( p - (p/q)*q , q ) != 1, 那么gcd ( p , q ) != 1 , 那么与p和q互质矛盾,所以p-(p/q)*q与q互质
这句话可能有些难理解 解释一下
若gcd(p-(p/q)*q,q)!=1;即 p-(p/q)*q与q不互质,,,那么设这个不为1公约数为o,,q=ow,
就得到了p-(p/q)*ow 和ow 都有o,所以p中必含o,,从而写成 o*(p/o -(p/q)*w)的形式 注:p/q看成一个常数;;;;
所以 p和q中都有o,所以gcd(p,q)!=1;
又因为设的p和q互质,,所以 gcd ( p - (p/q)*q , q ) != 1 不成立;;
所以 情况二 不成立;;
就证出了 只存在一种情况: p=(p除以q的商)*q 从而 gcd(a,b)=gcd(b,a%b);;;
int gcd(int a,int b)
{
if(b==0)return a;
gcd(b,a%b);
}
延伸算法:辗转相除法
扩展欧几里得算法:
先说一下逆元:
如图, x就是a在模m意义下的逆元( 逆元都是余数=1 );;
扩欧:
ax+by = gcd ( a , b )有无数组整数解 ;;;
作用,求x,y使上式成立(不一定最小);;;
证明:
用辗转相除算出gcd时,b=gcd,a%b=0,x1=1,y1=0;(以上一步的视角)
这时 a*x+b*y=gcd=bx1+(a%b)*y1
右边=bx1+ (a- (a/b)*b )*y1
=bx1+ a*y1- (a/b)*b*y1
=(y1)*a+ (x1 -(a/b)*y1)* b
又因为左边=(x)*a+ (y) *b
所以x=y1, y= x1 -(a/b)*y1;;;
......一直往上递归到顶层即求出了x和y;;;
就是反复用欧几里得定理,递归把a、b不断缩小,在将x、y往外扩;;;
void exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
daan=a;
return;
}
exgcd(b,a%b);
lin=y;
y=x-a/b*y;
x=lin;
}
至于求逆元:
1、 应用扩展欧几里得原理
若x是a关于m的逆元;;
那么 ax-my=1;
当然,需要m与a互质,,否则怎么模都不会剩1,于是无解;;
根据 ax+by=gcd(a,b)
设y=-y (⊙﹏⊙)b
得到 ax+my=1;;
用扩欧求出x
x就是a的逆元啦!!!
2、费马小定理:
a^(p-1)≡1(a%p)
期望:
(1)计算用性质:
期望的和=和的期望:
有1、2、3三种情况,出现1、2的期望=出现1的期望+出现2的期望;;;
适用于递推,递归,dp