(noip数论算法汇总)
①扩展欧几里得
int ex_gcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int g=ex_gcd(b,a%b,x,y);
int t=x;x=y,y=t-a/b*y;
return g;
}
应用及要点:
one : 求形如ax+by=gcd(a,b)的一组解(x,y) (有解情况当且仅当ab互质)
要注意的是,已知一组解(x0,y0),则其他所有解都可以表示成(x0+k*b,y0-k*a)
想像成直线就可以理解了
two: 求逆元,ax≡1 mod(p) 可以转化为 ax-py=1
另:
辗转相除和辗转相减法两个定理:
辗转相减法:gcd(a,b)=gcd(a-b,b)
辗转相除法:gcd(a,b)=gcd(a%b,b)
②分解质因数
O(sqrt(n))太无脑了无视掉
O(n)预处理和O(log(a))分解:
线性筛法预处理 dy[i] 表示i的最小质因子在prime数组中的编号
分解时每次除以最小质因子即可做到log的分解质因数
代码:
void init()
{
for(int i=2;i<=n;i++)
{
if(!vis[i])prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
long long tmp=prime[j]*i;
if(tmp>=N)break;
vis[tmp]=1,dy[tmp]=j;
if(tmp%prime[j]==0)break;
}
}
}
int num[N];
void work(int x)
{
while(x!=1)
{
num[dy[x]]++;
x/=prime[dy[x]];
}
}
③逆元:
常用的有三种,扩展欧几里得上面提到了,下面只写费马小定理和线性递推求逆元
费马小定理:a^(p-2)是a在膜p意义下的逆元,即a^(p-1)%p=1
ll qm(ll a,ll b)
{
ll ret=0,t=a;
while(b)
{
if(b&1)ret=ret*t%mod;
t=t*t%mod;b>>=1;
}return ret;
}
ll inv(ll x){return qm(x,mod-2); }
线性递推逆元: inv[1]=1,inv[i]=inv[p%i]*(p-p/i)%p
让我来认真的证明一次上式.....(noip前真的是差到连这玩意都不会证.......)
设 t=p/i,k=p%i
则 p=t*i+k
即 (t*i+k)≡0(mod p)
=> -t*i≡k(mod p)
两边同时除以i*k
=> -t*inv[k]≡inv[i](mod p)
故inv[i]=-t*inv[k](mod p)
转成正数:inv[i]=(-t+p)*inv[k](mod p)
所以 inv[i]=(p-p/i)*inv[p%i](mod p)
可以愉快的线性推逆元啦23333
int inv[N];
void init()
{
inv[1]=1;
for(int i=2;i
④欧拉函数:
线性筛求欧拉函数前面一篇博客里已经提到过,在此不提
欧拉函数的意义:
phi[n]=小于n的数中与n互质的数的个数
定义式:
phi[n]=n*(1-1/p1)*(1-1/p2)*(1-1/p3)....(1-1/pk)
这很简单就不放代码了。
应用:
one :上一个求逆元中还有一种方法没有说到就是欧拉函数。
有欧拉定理:a^φ(n) ≡ 1 mod n
two : 按定义,求小于n且与n互质的数的个数(2333)
three:求n以内与n互质的数的和
有公式:sum(n)=phi(n)*n/2; (sum(n)为小于n的所有与n互质的数的和)
⑤一些实用的定理:
约定:
唯一分解式形为n=p1^a1*p2^a2*p3^a3*…*pk^ak
约数个数定理: n的约数个数=(a1+1)*(a2+1)*(a3+1)....(ak+1)
约数和定理: n的约数和=(p1^0+p1^1+p1^2...p1^a1)*(p2^0+p2^1+p2^2....p2^a2)...(pk^0+pk^1...pk^ak)
基础的数论知识差不多就是这些了,后面几篇博客会对几个重要的数论知识点进行详解或较多例题复习
⑥等比数列求和的分治算法:
定理:
对于Sn=a^1+a^2+...+a^n
当n==0时Sn=1;n==1时Sn=a
当n为偶数时:
Sn=S(n/2)*(a^(n/2)+1)
当n为奇数时:
Sn=S(n/2)*(a^(n/2+1)+1)+(a^(n/2)+1)