您的位置:首页 > 其它

数♀论总♂结

2016-03-27 21:38 197 查看
太容易忘记数论的定理了,(也许是比较),所以开了个坑来记一下定理.

1.最大公因数,最小公倍数

gcd(a,b)=gcd(b,a%b) (最大公因数)

lcm(a,b)=a*b/gcd(a,b) (最小公倍数)

2.莫比乌斯反演

μ(x)={ 1 (x==1)

(-1)^k (x是由k个互不相同的质数相乘)

0 (其他情况)}

(莫比乌斯太难了,以后懂了记得填坑)

筛法求莫比乌斯函数

#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 60000+5;
bool vis[maxn];
int prime[maxn],primes,mu[maxn];
void init_mu()
{
memset(vis,0,sizeof(vis));
mu[1]=1;
primes=0;
for(int i=2; i<maxn; i++)
{
if(!vis[i]){
prime[primes++]=i;
mu[i]=-1;
}
for(int j=0; j<primes&&i*prime[j]<maxn; j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else { mu[i*prime[j]]=0;break;}
}
}
}


3.欧拉函数

欧拉函数属于积性函数(gcd(a,b)==1,f(a*b)=f(a)*f(b)),不是完全积性函数(任何情况 f(a*b)=f(a)*f(b))

若x为质数 phi(x)=x-1;

若x为奇数 phi(2*x)=phi(x)*2

若x为p^k,p为质数 phi(x)=x-x/p=p^k-p^(k-1)=(p-1)*p^(k-1) (因为除了p的倍数以外,都和x互质)

若a,b互质,b为质数,phi(a*b)=phi(a)*(b-1)

欧拉定理:若a,n互质 则有 a^(phi(n))= 1 (mod n)

O(n)筛法:

void get_phi()
{
int i, j, k;
k = 0;
for(i = 2; i < N; i++)
{
if(is_prime[i] == false)
{
prime[k++] = i;
phi[i] = i-1;
}
for(j = 0; j<k && i*prime[j]<N; j++)
{
is_prime[ i*prime[j] ] = true;
if(i%prime[j] == 0)
{
phi[ i*prime[j] ] = phi[i] * prime[j];
break;
}
else
{
phi[ i*prime[j] ] = phi[i] * (prime[j]-1);
}
}
}
}


4.exgcd

已知a,b求解x,y满足a*x+b*y=gcd(a,b)

若a==1,b==0 则x=1,y=0;

若已知下一层x,y

则当前t=x x=y y=t-a/b*y;

由于gcd(a,b)=gcd(b,a%b)

则有ax+by=bx+(a%b)y

ax+by=bx+(a-a/b*b)y

ax+by=ay+b*(x-a/b*y)

EXGCD求线性方程组:





5.原根

如果模p有原根,那么它一定有 phi(phi(p))个原根。

若有(g^i )%p(0<i<=p-1) 两两不同,则称g为p原根。

若p为素数,p一定有原根。g^(P-1) = 1 (mod P)(p为素数)

m有原根的充要条件:m=2,4,2*p^a,p^a 其中p为奇素数

原根通常很小,往往暴力求

求模素数p的原根:

对p-1质因数分解,分解成 p1^k1*p2^k2*p3^k3...pn^kn=p-1

对于一个数g若恒有 g^((p-1)/pi)!=1 (mod p)则g就是p的原根。

对合数p的原根:

讲上述p-1换成phi(p)即可。

6.逆♂元

若有a*x==1 (mod p),则称x是a在模p下的逆元

逆元运用广泛,可以进行转换等

6.1

(若a,p互质)a^phi(p)==1 (mod p) (费马小定理)

即有 a^(phi(p)-1)== a^(-1) (mod p)

即若p为质数,a在p下的逆元即是 (a^(p-2))%p;

6.2

若a/b中有b|a,现求a/b (mod p)

a/b=k*p+x (x即为a/b (mod p))

a=k*p*b+b*x

a%pb=b*x

x=(a%pb)/b

6.3

有些题目需要用到1->M 模M的所有逆元,我们有一个非常好♂用的顺推公式

inv[i]=(M-M/i)*inv[M%i]%M

证明如下:

设t=M/i,k=M%i

i*t+k=0 (mod M)

-i*t==k(mod M) 两边同时除以i*k得到

-t*inv[k]==inv[i](mod M)

inv[i]=-t*inv[k]将t=M/i,k=M%i带入可得上式

6.4

ax==b(mod p)

求最小解x

首先若gcd(a,p)不是b的因数则无解,否则将a,b带入exgcd(a,b,x,y)算出其中x即是满足上式的x

6.5

求阶乘的逆元?若p为素数

可以先让f
=((!n)%p)^(p-2)%p

然后从n-1往1:f[i]=f[i+1]*i%p就行辣!

简单来说就是先求 总阶乘的逆元,然后倒着乘回去

7.二次剩余

二次剩♂余:x^2== a(mod p)

有解则a为p的二次剩余,否则a是p的二次非剩余

若 a^((p-1)/2)==1(mod p)a是p的二次剩余

8.指标

指标:定义指标为I(A),那么I(A)就是最小令g^I(A)==A (mod p) 其中g是p的原根,若有x^a==b(mod c)则有 a*I(x)==I(b)(Mod(c-1)) PS:通常我们计算出原根基本都会用再预处理出指标

9.裴蜀定理

ax+by=gcd(a,b)一定有解

10.求幂大法和降幂大法

a^b Mod B=A^(b Mod phi(B)+phi(B)) %Mod B (其中b>=phi(B)) 求幂大法

p为素数 X^a%p=X^(a%(p-1))%p 降幂大法

11.组合数

运用广泛

11.1

杨辉三角:C[i][j]=C[i-1][j-1]+C[i-1][j] 计算时间O(N^2)

11.2

lucas定理 用于求C(n,m)%p, p为素数

Lucas(n,m)=C(n%p,m%p)*Lucas(n/p,m/p)

typedef long long LL;
using namespace std;

LL exp_mod(LL a, LL b, LL p) {
LL res = 1;
while(b != 0) {
if(b&1) res = (res * a) % p;
a = (a*a) % p;
b >>= 1;
}
return res;
}

LL Comb(LL a, LL b, LL p) {
if(a < b)   return 0;
if(a == b)  return 1;
if(b > a - b)   b = a - b;

LL ans = 1, ca = 1, cb = 1;
for(LL i = 0; i < b; ++i) {
ca = (ca * (a - i))%p;
cb = (cb * (b - i))%p;
}
ans = (ca*exp_mod(cb, p - 2, p)) % p;
return ans;
}

LL Lucas(int n, int m, int p) {
LL ans = 1;

while(n&&m&&ans) {
ans = (ans*Comb(n%p, m%p, p)) % p;
n /= p;
m /= p;
}
return ans;
}

int main() {
Read();
int n, m, p;
while(~scanf("%d%d%d", &n, &m, &p)) {
printf("%lld\n", Lucas(n, m, p));
}
return 0;
}


11.3

组合数取模?

C(n,m)=!n/(!(n-m)*!(m))

因此我们可以使用6.5中求阶乘逆元的方式,求出!(n-m)和!(m)在模下的逆元,然后相乘再乘上!n模模数就是答案!

12.BSGS (拔山盖世(雾))

a^x==b(mod p)

令x=i*m+j,其中m=ceil(sqrt(p)

a^(i*m+j)==b(mod p)

那么有

a^(j)==a^(-i*m)*b(mod p)其中a^(-i*m)就是a^(i*m)在模P下的逆元

那么我们只要枚举j,用哈希表存下 a^j %p,然后再枚举a^(-i*m)*b (mod p),在哈希表下查找就可以了

至于为什么要这样找和为什么m=ceil(sqrt(p)),我是不懂的。

13.质数

13.1 大于等于sqrt(n)的n的质因子不会超过一个

13.2 在!n内质因子p的出现个数为 n/p+n/(p^2)+n/(p^3)...+n/(p^k) (p^(k+1)刚好大于n)

13.3 筛法求质数

typedef long long LL;
#define mn 100000+5
LL ph[mn];
bool vis[mn];
int primes, prime[mn];
void Init()
{
ph[1] = 1;
primes=0;
for (LL i = 2; i < mn; ++i)
{
if (!vis[i])
{
prime[primes++] = i;
ph[i] = i-1;
}
for (LL j = 0; j < primes && i*prime[j] < mn; ++j)
{
vis[i*prime[j]] = true;
if (i % prime[j])
ph[i*prime[j]] = ph[i]*(prime[j]-1);
else
{
ph[i*prime[j]] = ph[i]*prime[j];
break;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: