有关取模,同余,逆元等的一些东西

在这里插入图片描述
在这里插入图片描述
刚看到一些东西,先记下来
持续更新,已经不止标题上面的那三个内容了。

a^-1表示a的逆元
a^2 ≡ b^2 (mod p), so a ≡ b (mod p)//这东西其实就是二次剩余,下面有;可以写一下cf447E
a ≡ b (mod p), so b ≡ a (mod p)
a ≡ b (mod p), so 1/b ≡ a^-1 (mod p)
a ≡ b (mod p), so a/c ≡ b*c^-1 (mod p) 
a ≡ b (mod p), so -a ≡ mod-b (mod p)

取模

void Add(LL &x, LL y){
  x += y; if(x>=mod)x-=mod;
}
void Sub(LL &x, LL y){
  x = x + mod - y; if(x>=mod)x-=mod;
}
void Mul(LL &x, LL y){
  x *= y; if(x>=mod)x%=mod;
}
(a / b) % p = (a % (p*b)) / b

a b      m o d      p    =    d \frac{a}{b}\;\;mod\;\;p\;=\;d bamodp=d
a b      =    p x + d \frac{a}{b}\;\; =\;px + d ba=px+d
a    =    p b x + b d a\;=\;pbx + bd a=pbx+bd
a    m o d    p b    =    b d a\;mod\;pb\;=\;bd amodpb=bd
a    m o d    p b b    =    d \frac{a\;mod\;pb}{b}\;=\;d bamodpb=d
a b      m o d      p    =    a    m o d    p b b \frac{a}{b}\;\;mod\;\;p\;=\;\frac{a\;mod\;pb}{b} bamodp=bamodpb


同余, CRT

x = sigma (ri*(M/ai)*inv(M/ai,ai)) % MOD

N ≡ r1(mod a1) N ≡ r2(mod a2)...
考虑前两个式子N = r1+a1*x = r2+a2*y --> a1*x - a2*y = r2-r1 = R
a1/gcd*x=R/gcd+a2/gcd*y,也就是a1/gcd*x≡R/gcd mod(a2/gcd)exgcd(a1/gcd,a2/gcd,d',X,Y)得到a1/gcd*X+a2/gcd*Y=1的一组解(X,Y)
X = inv(a1/gcd,a2/gcd)
x ≡ X*(R/gcd) mod(a2/gcd) -> x ≡ (R/gcd)*X+t*(a2/gcd)
回代到第一个式子:N = X*(R/gcd)*a1+r1+t*a1*a2/gcd
化简:N ≡ X*(R/gcd)*a1+r1 mod(a1*a2/gcd)
得到新的方程式:r1 = a1*X*R/gcd + r1, a1 = a1*a2/gcd


int CRT(){
    int flag=0,a1=ar[1],r1=r[1],R,d,x,y,dm;
    for(int i=2;i<=n;++i){
        exgcd(a1,ar[i],d,x,y);
        R=r[i]-r1;
        if(R%d){flag=1;break;}
        dm=ar[i]/d;
        x=((x*R/d)%dm+dm)%dm;
        r1=a1*x+r1;a1=a1*dm;
    }
    return r1;
}

逆元
以下两种方法必须满足 a a a p p p互质才能求出逆元
a × b ≡ 1    ( m o d    p ) a \times b ≡ 1\;(mod\;p) a×b1(modp) a , b a, b a,b互为模 n n n意义下的逆元。 x / a = x × b % p x/a=x\times b\%p x/a=x×b%p
容易得到: a × b + k × p = 1 a\times b+k\times p=1 a×b+k×p=1,由 e x g c d exgcd exgcd可以轻松得到 a a a的逆元。

费马小定理
若p为素数,则 a^(p-1) = 1 (mod p)
a * a^(p-2) = 1 (mod p)
a 的逆元 = a^(p-2) % p

ϕ(p) = p - 1
当x≥ϕ(p)时,有a^x ≡ a^(x mod ϕ(p)+ϕ(p)) mod p
gcd(a,mod)=1  a^(x) = a^(x%ϕ(mod)) % mod
if x>=ϕ(mod) && gcd(a,mod)!=1  a^(x) = a^(x%ϕ(mod) + ϕ(mod)) % mod
if x<ϕ(mod) && gcd(a,mod)!=1  a^(x) = a^(x%ϕ(mod)) % mod

欧拉定理:若a, p互素, a^ϕ(p) = 1(mod p), a模p意义下的逆元 = a^(ϕ(p) - 1)

void exgcd(int a,int b,int &d,int &x,int &y){
  if(b == 0){
    x = 1; y = 0; d = a;
    return;
  }
  exgcd(b, a % b, d, y, x);
  y -= a / b * x;
}
a的逆元 = (x % mod + mod) % mod

预处理x的逆元

void getinv(){//mod为素数
  inv[1] = 1;
  for(int i = 2; i < N; ++i)
    inv[i] = (MOD-MOD/i) * 1LL * inv[MOD%i] % MOD;
}
LL inv(LL t, LL p){//求t关于p的逆元
    return t==1?1: (p-p/t) * inv(p % t, p) % p;
}

预处理x!的逆元

LL ksm(LL a, int b) {
    LL res = 1;
    for(; b; b>>=1, a=a*a%mod) {
        if(b&1) res = res * a % mod;
    }
    return res;
}

const int MAXN = 1e6 + 6;
LL F[MAXN], invF[MAXN];
void init_comb() {
	F[0] = 1;
	for (int i = 1; i < MAXN; i++) F[i] = F[i - 1] * i % mod;//阶乘
	invF[MAXN - 1] = ksm(F[MAXN - 1], mod - 2);
	for (int i = MAXN - 2; i >= 0; i--) invF[i] = invF[i + 1] * (i + 1) % mod;//阶乘的逆元
}
LL COMB(int n, int m) {//组合数
	if(n < m) return 0; if(n == m)return 1;
	return F[n] * invF[m] % mod * invF[n-m] % mod;
}

const int MAXN = 1e6 + 6;
LL fac[MAXN], facInv[MAXN], inv[MAXN];
void init_comb() {
	inv[1] = 1;//逆元
	fac[0] = facInv[0] = 1;//阶乘和阶乘的逆元
	for(int i = 1; i < MAXN; ++i) {
	    if(i != 1) inv[i] = (mod - mod / i)*inv[mod % i] % mod;
	    fac[i] = fac[i-1] * i % mod;
	    facInv[i] = facInv[i-1] * inv[i] % mod;
	}
}
LL COMB(int n, int m) {//组合数
	if(n < m) return 0; if(n == m)return 1;
	return fac[n] * facInv[m] % mod * facInv[n-m] % mod;
}

这里还有很多东西:here


gcd && Exgcd

void exgcd(LL a, LL b, LL &d, LL &x, LL &y) {
  if(b == 0){
    x = 1; y = 0; d = a;
    return;
  }
  exgcd(b, a % b, d, y, x);
  y -= a / b * x;
  return;
}

反素数

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL pp[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
LL ans, n, MAXY;
//求n以内因子最多的数,多个答案输出小的
void dfs(LL Y, LL dep, LL num, LL limit){
    //因子数 深度 当前的数
    if(dep == 16)return;
    //if(Y >= n) return;//n个因数的最小整数
    if(Y > MAXY) MAXY = Y, ans = num;
    if(Y == MAXY) ans = min(ans, num);
    for(int i = 1; i <= limit; ++i){
        //因为后面的次数不会超过前面,所以这里添加上限就是一个极大的剪枝
        if(n / pp[dep] < num) break;//保证不超过n
        dfs(Y*(i+1), dep+1, num*=pp[dep], i);
    }
}
int main(){
    int tim; scanf("%d", &tim);
    while(tim --){
        scanf("%lld",&n);
        ans = 1e18;
        MAXY = 0;
        dfs(1, 0, 1, 60);
        printf("%lld %lld\n", ans, MAXY);
    }
}

二次剩余

记一些结论及方法,不做证明(因为不会

参考:SFN1036Eiffel灬

定义:若方程 x 2 ≡ a ( m o d    p ) x^2≡a(mod\;p) x2a(modp)有解,则称 a a a为模 p p p的二次剩余;反之称为 a a a为模 p p p的非二次剩余。
x x x为二次同余方程的解。

因此:由 x 2 ≡ a ( m o d    p ) x^2≡a(mod\;p) x2a(modp)可以推出 x ≡ a ( m o d    p ) x≡\sqrt a(mod\;p) xa (modp) a a a可以模p的意义下开根号。

勒让德符号:
( n p ) = { 1 n为模p的二次剩余 − 1 n为模p的非二次剩余 0 a≡0(mod    p) (\frac{n}{p})= \begin{cases} 1& \text{n为模p的二次剩余}\\ -1& \text{n为模p的非二次剩余}\\ 0& \text{a≡0(mod\;p)} \end{cases} (pn)= 110n为模p的二次剩余n为模p的非二次剩余a≡0(modp)
欧拉判别法: ( n p ) = a p − 1 2 ( m o d    p ) (\frac{n}{p})=a^{\frac{p-1}{2}}(mod\;p) (pn)=a2p1(modp)

定理1: x 2 ≡ a ( m o d    p ) x^2≡a(mod\;p) x2a(modp)共有 p − 1 2 + 1 \frac{p-1}{2}+1 2p1+1 n n n的值使得方程有解。其中 + 1 +1 +1代表 n = 0 n=0 n=0的情况。
在这里插入图片描述
定理2: ( a + b ) p ≡ a p + b p ( m o d    p ) (a+b)^p≡a^p+b^p(mod\;p) (a+b)pap+bp(modp)

证明:通过二项式展开可以得到: ( a + b ) p = ∑ k = 0 p C p k a k b p − k (a+b)^p=\sum_{k=0}^{p}C_{p}^{k}a^kb^{p-k} (a+b)p=k=0pCpkakbpk
k k k不等于 p p p且不为 0 0 0时, C p k C_{p}^{k} Cpk中的 p p p是不可能被消掉的,于是就会在取模时被消掉。

Cipolla算法:
设 a 满足 ω = a 2 − n 是模 p 的非二次剩余,即 x 2 ≡ ω ( m o d    p ) 无解。那么 x = ( a + ω ) p + 1 2 是二次同余方程 x 2 = n ( m o d    p ) 的解。 设a满足\omega =a^2-n是模p的非二次剩余,即x^2≡\omega(mod\;p)无解。那么x=(a+\sqrt \omega)^{\frac{p+1}{2}}是二次同余方程x^2=n(mod\;p)的解。 a满足ω=a2n是模p的非二次剩余,即x2ω(modp)无解。那么x=(a+ω )2p+1是二次同余方程x2=n(modp)的解。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define random(a,b) (rand()%(b-a+1)+a)
LL quick_mod(LL a, LL b, LL c) { LL ans = 1; while (b) { if (b % 2 == 1)ans = (ans*a) % c; b /= 2; a = (a*a) % c; }return ans; }

LL p;
LL w;//二次域的D值
bool ok;//是否有解
//二次域
struct QuadraticField {
    LL x, y;
    //二次域乘法重载
    QuadraticField operator*(QuadraticField T) {
        QuadraticField ans;
        ans.x = (this->x*T.x%p + this->y*T.y%p*w%p) % p;
        ans.y = (this->x*T.y%p + this->y*T.x%p) % p;
        return ans;
    }
    //二次域快速幂
    QuadraticField operator^(LL b) {
        QuadraticField ans;
        QuadraticField a = *this;
        ans.x = 1;
        ans.y = 0;
        while (b) {
            if (b & 1) {
                ans = ans*a;
                b--;
            }
            b /= 2;
            a = a*a;
        }
        return ans;
    }
};
//求勒让德符号
LL Legender(LL a) {
    LL ans=quick_mod(a, (p - 1) / 2, p);
    if (ans + 1 == p)//如果ans的值为-1,%p之后会变成p-1。
        return -1;
    else
        return ans;
}
//根据随机出来a的值确定对应w的值
LL Getw(LL n, LL a) {
    return ((a*a - n) % p + p) % p;//防爆处理
}

LL Solve(LL n) {
    LL a;
    if (p == 2)//当p为2的时候,n只会是0或1,然后0和1就是对应的解
        return n;
    if (Legender(n) == -1)//无解
        ok = false;
    srand((unsigned)time(NULL));
    //随机a的值直到有解
    while (1) {
        a = random(0, p - 1);
        w = Getw(n, a);
        if (Legender(w) == -1)
            break;
    }
    QuadraticField ans,res;
    res.x = a;
    res.y = 1;//res的值就是a+根号w
    ans = res ^ ((p + 1) / 2);
    return ans.x;
}
int main() {
    LL n,ans1,ans2;
    while (scanf("%lld%lld",&n,&p)!=EOF) {
        ok = true;
        n %= p;
        ans1 = Solve(n);
        ans2 = p - ans1;//一组解的和是p
        if (!ok) {
            printf("No root\n");
            continue;
        }
        if (ans1 == ans2)
            printf("%lld\n", ans1);
        else
            printf("%lld %lld\n", ans1, ans2);
    }
}

欧拉降幂

a^φ(m)1(mod m) gcd(a,m)=1
gcd(a,mod)=1  a^(x)=a^(x%ϕ(mod)) %mod
gcd(a,mod)!=1  a^(x)=a^(x%ϕ(mod)+ϕ(mod)) %mod  only if x>=ϕ(mod)
gcd(a,mod)!=1  a^(x)=a^(x%ϕ(mod)) %mod  only if x<ϕ(mod)

广义二项式定理

单纯的记一下而已。

推论1:当 ∣ x ∣ < 1 |x|<1 x<1时,有 1 1 + x = ∑ k = 0 ∞ ( − 1 ) k x k \frac{1}{1+x}=\sum_{k=0}^{∞}(-1)^kx^k 1+x1=k=0(1)kxk

推论2:当 ∣ x ∣ < 1 |x|<1 x<1时,有 1 1 − x = ∑ k = 0 ∞ x k \frac{1}{1-x}=\sum_{k=0}^{∞}x^k 1x1=k=0xk

推论3:当 ∣ x ∣ < 1 |x|<1 x<1时,有 1 + x = 1 + ∑ k = 1 ∞ ( − 1 ) k − 1 2 2 k − 1 k ( k − 1 2 k − 2 ) x k \sqrt{1+x}=1+\sum_{k=1}^{∞}\frac{(-1)^{k-1}}{2^{2k-1}k}(_{k-1}^{2k-2})x^k 1+x =1+k=122k1k(1)k1(k12k2)xk


解决一类离散对数问题
https://blog.csdn.net/qq_18869763/article/details/99004531

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值