数♀论总♂结

太容易忘记数论的定理了,(也许是比较),所以开了个坑来记一下定理.

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               (其他情况)}

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

 筛法求莫比乌斯函数

 1 #include <cstdio>  
 2 #include <cstring>  
 3 using namespace std;  
 4 const int maxn = 60000+5;  
 5 bool vis[maxn];  
 6 int prime[maxn],primes,mu[maxn];  
 7 void init_mu()  
 8 {  
 9     memset(vis,0,sizeof(vis));  
10     mu[1]=1;  
11     primes=0;  
12     for(int i=2; i<maxn; i++)  
13     {  
14         if(!vis[i]){  
15             prime[primes++]=i;  
16             mu[i]=-1;  
17         }  
18         for(int j=0; j<primes&&i*prime[j]<maxn; j++)  
19         {  
20             vis[i*prime[j]]=1;  
21             if(i%prime[j]) mu[i*prime[j]]=-mu[i];  
22             else { mu[i*prime[j]]=0;break;}  
23         }  
24     }  
25 }  

-2016-06-20 终于看懂一点点。。。,

    这玩意常常用来求gcd的关系。

    f(i)是i=gcd(x,y),g(i)是i|gcd(x,y)

    那么f(n)=d|n  u(n/d)*g(d)

如果有式子满足f(n)=Σ d|n a(d)*b(n/d)

我们通常表示为f=a*b,这是卷积的表示,其中,如果f(n)=Σ d|n a(d),那么我们表示为f=a*1,

1实际上代表单位卷积。1*1代表的是除数函数中x等于0的情况:

卷积满足交换律和结合律。。

-2016-06-20

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)筛法:

  

 1 void getphi()
 2 {
 3     phi[1]=1;
 4     for(int i=2;i<=n;i++)
 5     {
 6         if(!mark[i]){phi[i]=i-1;pri[++tot]=i;}
 7         for(int j=1;j<=tot;j++)
 8         {
 9             int x=pri[j];
10             if(i*x>n)break;
11             mark[i*x]=1;
12             if(i%x==0){phi[i*x]=phi[i]*x;break;}
13             else phi[i*x]=phi[i]*phi[x];
14         }
15     }
16 }
 1 //直接求解欧拉函数  
 2 int euler(int n){ //返回euler(n)   
 3       int res=n,a=n;  
 4       for(int i=2;i*i<=a;i++){  
 5           if(a%i==0){  
 6               res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出   
 7               while(a%i==0) a/=i;  
 8           }  
 9       }  
10       if(a>1) res=res/a*(a-1);  
11       return res;  
12  }  

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)

注意:如求某数N的逆元,则令a=N,b=p(假如是在模p下),如果令b=0会错误.

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]=((!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) 

 1 typedef long long LL;
 2 using namespace std;
 3 
 4 LL exp_mod(LL a, LL b, LL p) {
 5     LL res = 1;
 6     while(b != 0) {
 7         if(b&1) res = (res * a) % p;
 8         a = (a*a) % p;
 9         b >>= 1;
10     }
11     return res;
12 }
13 
14 LL Comb(LL a, LL b, LL p) {
15     if(a < b)   return 0;
16     if(a == b)  return 1;
17     if(b > a - b)   b = a - b;
18 
19     LL ans = 1, ca = 1, cb = 1;
20     for(LL i = 0; i < b; ++i) {
21         ca = (ca * (a - i))%p;
22         cb = (cb * (b - i))%p;
23     }
24     ans = (ca*exp_mod(cb, p - 2, p)) % p;
25     return ans;
26 }
27 
28 LL Lucas(int n, int m, int p) {
29      LL ans = 1;
30 
31      while(n&&m&&ans) {
32         ans = (ans*Comb(n%p, m%p, p)) % p;
33         n /= p;
34         m /= p;
35      }
36      return ans;
37 }
38 
39 int main() {
40     Read();
41     int n, m, p;
42     while(~scanf("%d%d%d", &n, &m, &p)) {
43         printf("%lld
", Lucas(n, m, p));
44     }
45     return 0;
46 }

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    筛法求质数

 1 typedef long long LL;  
 2 #define mn 100000+5  
 3 LL ph[mn];  
 4 bool vis[mn];  
 5 int primes, prime[mn];  
 6 void Init()  
 7 {  
 8     ph[1] = 1;  
 9     primes=0;  
10     for (LL i = 2; i < mn; ++i)  
11     {  
12         if (!vis[i])  
13         {  
14             prime[primes++] = i;  
15             ph[i] = i-1;  
16         }  
17         for (LL j = 0; j < primes && i*prime[j] < mn; ++j)  
18         {  
19             vis[i*prime[j]] = true;  
20             if (i % prime[j])  
21                 ph[i*prime[j]] = ph[i]*(prime[j]-1);  
22             else  
23             {  
24                 ph[i*prime[j]] = ph[i]*prime[j];  
25                 break;  
26             }  
27         }  
28     }  
29 }  

    这个算法的关键在于 if(i%pr[j] == 0) break;。它使得任何一个合数,只被它最小的质因数标记过一次

      

       

原文地址:https://www.cnblogs.com/qzqzgfy/p/5326949.html