初等数论


前言:

如何评价 OI 逐渐 MO 化。

我数学不是很好,最近学了这玩意,写一篇总结。

$\text{Part I 素数筛} $

  • 埃式筛 Eraosthenes

    • 大概思路:从2开始,由小到大扫描每一个数 \(x\),把他的倍数标记为合数。当扫描到一个数时,若尚未被标记,那么就是质数。
    • 复杂度:\(O(n \log \log n)\) 接近线性。
    • 代码:
      void make_prime()
      {
          memset(prime,true,sizeof(prime));
          prime[0]=prime[1]=false;//0,1都不是素数 
          int t=sqrt(n);//开根号 
          for(int i=2;i<=t;i++)
          {
              if(prime[i])
              {
                  for(int j=2*i;j<=n;j+=i)//加倍 
                  {
                      prime[j]=false;
                  }
              }
          }
          return;
      }  
  • 线性筛

    • 大致思路:从小到大积累质因子
    • 复杂度:\(O(n)\)
  void init() {
    phi[1] = 1;
    for (int i = 2; i < MAXN; ++i) {
      if (!vis[i]) {
        phi[i] = i - 1;
        pri[cnt++] = i;
      }
      for (int j = 0; j < cnt; ++j) {
        if (1ll * i * pri[j] >= MAXN) break;
        vis[i * pri[j]] = 1;
        if (i % pri[j]) {
          phi[i * pri[j]] = phi[i] * (pri[j] - 1);
        } else {
          // i % pri[j] == 0
          // 换言之,i 之前被 pri[j] 筛过了
          // 由于 pri 里面质数是从小到大的,所以 i 乘上其他的质数的结果一定会被
          // pri[j] 的倍数筛掉,就不需要在这里先筛一次,所以这里直接 break
          // 掉就好了
          phi[i * pri[j]] = phi[i] * pri[j];
          break;
        }
      }
    }
  }

$\text{Part II Prime Numbers and Phi} $

\(\phi(n)\) 表示 \(1~n\) 中与 \(n\) 互质的个数。同时也是欧拉函数。

然后有很多好玩的性质,由于我 \(\LaTeX\) 实在不大行就先不写了。

代码:

void euler(int n)
{
	for(int i=2;i<=n;i++) ph[i]=i;
	for(int i=2;i<=n;i++)
	{
		if(ph[i]==i)
		{
			for(int j=i;j<=n;j+=i)
			{
				ph[j]=ph[j]/i*(i-1);
			}
		}
	}
}

$\text{Part III 欧几里得} $

  • \(\gcd\):欧几里得算法,俗称辗转相除。
int gcd(int a,int b)
{
    return b ? gcd(b,a%b) : a;
}
  • 扩展欧几里得:对于任意整数 \(a,b\) ,存在一对整数 \(x,y\) ,满足 \(ax+by=\gcd(a,b)\) 。不过说句闲话,这个应该裴蜀定理。解这个方程算法被称之为“扩展欧几里得”。
int exgcd(int a,int b,int &x,int &y)
{
	if(a==0)
	{
		x=0;y=1;
		return b;
	}
	int d=exgcd(b%a,a,y,x);
	x-=b/a*y;
	return d;
}

提一嘴逆元:若整数 \(b,m\) 互质,且 \(b|a\),则存在一个整数 \(x\),使得 \(\frac{a}{b}\)\(a\times x\)\(m\) 同余。则称 \(x\)\(b\) 的模 \(m\) 乘法逆元。然后这玩意一般都是用来转换除法的。

$\text{Part IIII 同余方程} $

对于像 ACwing203 这种题直接用欧几里得算法求出一种特解,然后就最小值即可。

中国剩余定理:

直接放代码:

/*long long gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}*/
#include<cstdio>
#define ll long long
//扩展欧几里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){
        d=a;
        x=1,y=0;
    }
    else{//else不能省略 
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
//中国剩余定理 
ll China(int n,ll *m,ll *a)
{
    ll M=1,d,y,x=0;
    for(int i=0;i<n;i++) M*=m[i];
    for(int i=0;i<n;i++){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}
ll m[15],a[15];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lld%lld",&m[i],&a[i]);
    printf("%lld",China(n,m,a));
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM