余数定理学习指南

前置芝士

乘法逆元

a存在模p的乘法逆元的充要条件是gcd(a,p)=1,即a与p互质。

若a,b不互素,则a必然不存在模b的逆元。

0没有逆元

余数性质

如果a,b除以m的余数相同,那么a与b的差是m的倍数。(作差是为了消掉余数)

剩余类

给定一个正整数 n,把所有整数根据模 n的余数 r[0,n1]分为 n 类,每一类数都是诸如 Cr=nx+r, 的形式,这样的一类数所构成的一个集合称为模 n的剩余类。

剩余系

给定一个正整数 n,有 n个不同的模 n的剩余类,从中任选 x个不同的剩余类,从这 x个剩余类中各取出一个元素,总共 x 个数,将这些数构成一个新的集合,则称这个集合为模 n的剩余系。

完全剩余系

给定一个正整数 n,有 n个不同的模 n的剩余类,从这 n个不同的剩余类中各取出一个元素,总共 n个数,将这些数构成一个新的集合,则称这个集合为模 n的完全剩余系。、

我们取 n=5,则 {0,1,2,3,4}是一个模 5的完全剩余系,{5,1,8,−3,14}也是一个模5 的完全剩余系。

对于一个模 n的完全剩余系 r,若有 a∈Z, b∈Z,且 gcd(n,a)=1,则 \(a∗r_i+b (i∈[0,n−1])\)也构成一个模 n 的完全剩余系。

简化剩余系

给定一个正整数 n,有 φ(n)个不同的、模 n的余数 rn互质的剩余类,从这 φ(n)个剩余类中各取出一个元素,总共 φ(n)个数,将这些数构成一个新的集合,则称这个集合为模 n的简化剩余系。

我们取 n=10,则 {1,3,7,9} 是一个模 10的简化剩余系。

[性质1]

对于一个模 n 的简化剩余系 r,若有 a∈Z且 gcd(n,a)=1,则 \(a∗r_i\)也构成一个模 n 的简化剩余系。

[证明]

因为(a,m)=1,(x,m)=1,于是(ax,m)=1。故ax为m的简化剩余类的剩余。

因为φ(n)是固定不变的,只要通过反证法证明\(ax_{1},ax_{2},\ldots,ax_{\phi(m)}\)\(\phi(m)\)个数模m两两不同余即可。若存在\(x_i\)\(x_j\),i!=j,使得\(ax_i\equiv ax_j(modm)\)

若上面等式成立,需要满足\(m | a(x_i-x_j)\),由于gcd(a,m)=1,所以\(x_i \equiv x_j(modm)\),这与\(x_{1},x_{2},\ldots,x_{\phi(m)}\)模m两两不同余矛盾。因此,ax也是模m的一个简化剩余系。

互质对

如果整数x和y的最大公因数是1,则称(x,y)为互质对。

有理数

。。。。。。

分数

[判断分数是有限小数]

一个最简分数,分母的质因数中只有2或5,这个分数一定能化成有限小数

扩展欧几里得

x的第一个正解就是(x%k+k)%k,其中,k=b/gcd(a,b)

[值域分析]

ax+by=gcd(a,b)的解法有无数个,显然其中有的解会爆long long

但万幸的是,若\(b\neq0\),扩展欧几里得算法求出的可行解必有\(|x|\leq b,|y|\leq a\)

// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= (a/b) * x;
    return d;
}

欧拉函数

欧拉函数φ(n) 是小于或等于n的正整数中与n互质的数的数目。

公式:\(\phi(x)=x(1-\frac1{p_1})(1-\frac1{p_2})\cdots(1-\frac1{p_n})\text{,其中 }p_1,p_2\cdots p_n\text{ 是 }x\text{ 的所有质因数。}\)

[性质]

(1)积性函数,但不完全积性函数

当n,m互质时,满足\(ϕ(nm)=ϕ(n)*ϕ(m)\)

当n根据算术基本定理分解为\(n=p_1^{c1}p_2^{c2}\ldots p_m^{cm}\)时,\(\phi(n)=\prod_{i=1}^m\phi(p_i^{ci})\)

【证明】

若n与m互质,则n与m没有相同的质因子设n的质因子个数为\(cnt_n\),m的质因子个数为\(cnt_m\),则

\[\begin{aligned} &\phi(n)*\phi(m)&=n*\prod_{i=1}^{cnt_n}(1-p_i)*m*\prod_{i=1}^{cnt_m}(1-p_i) &=n*m*\prod_{i=1}^{cnt_n+cnt_m}(1-p_i) &=\phi(nm) \end{aligned} \]

(2)对于质数p,它的欧拉函数值ϕ(p)=p−1

[证明]

因为p为质数,所以比它小的数都和它互质,即在1~p中共有p-1个数和它互质。

(3)当n为奇数时,ϕ(2∗n)=ϕ(n)

[证明]

当n为奇数时,n与2互质,由欧拉函数是积性函数可知,n与2互质时,\(\phi(2n)=\phi(2)*\phi(n)\)

又因为ϕ(2)=1,所以ϕ(2n)=ϕ(n).

(4)\(n=p^k\),\(\phi(n)=p^k-p^{k-1}\)

(5)n中与n互质的数的和为\(\phi(n)\div2\times n(n>1)\),并且ϕ(n)(n>2)为偶数。

(6)\(\text{若}p|n\text{且}p^2|n\text{,则}\phi(n)=\phi(\frac np)*p\)\(\text{若}p|n\text{且}p^2\nmid n,\text{则}\phi(n)=\phi(\frac np)*(p-1)\)

(7)\(\sum_{d|n}\phi(d)=n\)

(8)\(\phi(n)=\sum_{d|n}\frac{\mu(d)}d\)

欧拉定理

[定义]

\(\text{若}\gcd(a,m)=1\text{,则 }a^{\varphi(m)}\equiv1\mathrm{~(mod~}m)。\)

费马小定理\(a^{p-1}\equiv1\textit{ ( mod p)}\),其中gcd(a,p)=1,是欧拉定理的一种特性。

[证明]

。。。。。。

扩展欧拉定理

[公式]

\[a^b\equiv\begin{cases}a^{b\operatorname{mod}\varphi(m)},&\gcd(a,m)=1,\\a^b,&\gcd(a,m)\neq1,b<\varphi(m),&\mathrm{(mod~}m)\\a^{(b\operatorname{mod}\varphi(m))+\varphi(m)},&\gcd(a,m)\neq1,b\geq\varphi(m).&\end{cases} \]

[证明]

。。。。。。

快速幂

递归方式:log(n)

【思路分析】

\(x^{n}\): ①若n为偶数,\(x^{n} = x^{n/2} *x^{n/2} ∗ x^{(n/2)*2}\); ②若n为奇数,\(x^{n}=x^{n/2}*x^{n/2}*x\)

//c++ 递归
int qmi(int x,int n){
    if(n==0) return 1;
    int res=qmi(x,n/2);
    return n%2==0?y*y:y*y*x;
}

迭代方式:log(n)

【思路分析】

\(x^{11}\): 11的二进制:1011,于是\(x^{11}= x^{(2^0 + 2^1 + 2^3)}=x^{( 2^0 )}*x^{(2^1)}*x^{(2^3)}x= x * x ^{2}*x^{8}\), 只要分别求x^i再相乘,不用将x连乘11次。

//c++ lambda while
auto qmi=[](int a,int k,int p){
       ll res=1%p,t=a;
       while(k){
           if(k&1) res=res*t%p;
           t=t*t%p;
           k>>=1;
       } 
       return res;
    };

快速幂(小数、不含取模)

-100.0<x<100.0

\({-2}^{31}<=n<=2^{31}-1\)

double qmi(double x,ll n){
    ll en=n;
    if(n<0) en=-n;
    double res=1;
    while(en){
        if(en&1) res*=x;
        x*=x;
        en>>=1;
    }
    if(n>0) return res;
    return 1.0/res;
}

BSGS算法

给定一个质数 \(p\),以及一个整数 \(a\),一个整数 \(b\),现在要求你计算一个最小的非负整数 \(x\),满足 \(a^x \equiv b \pmod p\)

Baby Step Giant Step

(1)由扩展欧拉定理\(a^{x}\equiv a^{xmod\varphi(p)}(modp)\),可知\(a^x\)模p意义下的最小循环节为\(\varphi({p})\),因\(\varphi(p)<{p}\),故考虑\(x\in[0,p]\),必能找到最小整数x。

(2)暴力枚举的时间复杂度为O(p)的。

(3)令\(x=im-j\),其中\(m=\lceil\sqrt{p}\rceil,i\in[1,m],j\in[0,m-1]\)

\(a^{im-j}\equiv b(modp)\),转化为\((a^{m})^{i}\equiv ba^{j}(modp)\)

(4)先枚举j,把(ba^j,j)丢进哈希表,如果key重复,用更大的j代替旧值。

(5)再枚举i,计算\((a^m)^i\),在哈希表中查找是否又相等的key,找到第一个即结束,则最小的x=im-j。

扩展BSGS算法

给定 \(a,p,b\),求满足 \(a^x≡b \pmod p\) 的最小自然数 \(x\)

[解题步骤]

(1)当a,p互质时,可以使用BSGS算法求解。

(2)当a,p不互质时,想办法让他们变得互质。

(3)原方程等价于\(a*a^{x-1}+py=b\)

\(d_1=gcd(a,p),如果\)\(d_{1}\nmid b\),则原方程无解。

否则方程两边同时除于\(d_1\),得\(\frac{a}{d_{1}}a^{x-1}\equiv\frac{b}{d_{1}}\left(mod\frac{p}{d_{1}}\right)\)

如果a和\(\frac p{d_1}\)仍不互质再除

\(d_2=\gcd(\mathrm{a},\frac{p}{d_1})\)\(d_{2}\nmid \frac{b}{d1}\),则原方程无解。

或者方程两边需要同时除于\(d_2\),得\(\frac{a^{2}}{d_{1}d_{2}}a^{x-2}\equiv\frac{b}{d_{1}d_{2}}\left(mod\frac{p}{d_{1}d_{2}}\right)\)

不停的判断下去,直到\(a\perp\frac{p}{d_{1}\cdots d_{k}}\),记\(D=\prod_{i=1}^{k}d_{i}\)

原方程变为\(\frac{a^{k}}{D}a^{x-k}\equiv\frac{b}{D}\left({\operatorname*{mod}}{\frac{p}{D}}\right)\)

\(a\perp\frac pD\),则\(\frac{a^{k}}{D}\perp\frac{p}{D}\),则\(\frac{a^k}D\)就有逆元了,把它丢到方程右边,就是一个标准的BSGS问题了,求解出x-k后再加上k就ok了。

\[\frac{a^{k}}{D}a^{x-k}\equiv\frac{b}{D}\left({\operatorname*{mod}}{\frac{p}{D}}\right)=Aa^{im-j}\equiv b^{\prime}(modp^{\prime}) \]

求解正整数n的欧拉函数

O(sqrt(n))

//求n的欧拉函数值
int phi(int n){
    int res=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            res=res/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) res=res/n*(n-1); 
    return res;
}

求解[1,n]区间的欧拉函数值(线性筛)

O(nlognlogn)

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

O(n)

const int N = 10000010;
int phi[N];
ll sum[N];
bool vis[N];
int pr[1000010], idx;
void init(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i])
            pr[idx++] = i, phi[i] = i - 1;
        for (int j = 0; j < idx && pr[j]*i <= n; j++) {
            vis[i*pr[j]]=1;
            if(i%pr[j]==0){
                phi[i*pr[j]]=phi[i]*pr[j];
                break;
            }else{
                phi[i*pr[j]]=phi[i]*phi[pr[j]];
            }
        }
    }
}

求解[l,r]范围区间的欧拉函数值

计算小于等于x的数中,与x不互质的数的个数。

(\(1\leq l\leq r\leq10^{12},r-l\leq10^6\))

O(r-l)

const int N = 1e6 + 10;
const ll mod = 666623333;
int pr[N], cnt;//保存的是每一个质数,以及个数cnt
bool vis[N];
void get_pr(int n) {
    for (int i = 2; i<= n; i++) {
        if (!vis[i]) pr[cnt++] = i;
        for (int j = 0; pr[j] <= n / i; j++) {
            vis[pr[j]*i] = true;
            if (i % pr[j] == 0) break;
        }
    }
}
// N=1e6 + 10;
vector<int> ans[N];
ll phi[N];
void solve() {
    ll l, r, res=0;
    cin>>l>>r;
    get_pr((int)sqrt(r));//预处理出<=sqrt(r)的质数
    for(int i=0;i<cnt;i++){
        int p=pr[i];
        for(ll j=((l-1)/p+1)*p;j<=r;j+=p)
            ans[j-l].push_back(p);
    }
    for(ll i=l;i<=r;i++){
        ll tmp=i;
        phi[i-l]=i;
        for(int p:ans[i-l]){
            phi[i-l]=phi[i-l]/p*(p-1);
            while(tmp%p==0) tmp/=p;
        }
        if(tmp>1) phi[i-l]=phi[i-l]/tmp*(tmp-1);
        //phi:互质的数
        //i-phi:不互质的数
        res=(res+i-phi[i-l])%mod;
    }
    cout<<res<<endl;
}

高精模幂数降幂

费马小定理降幂

推论 若p为素数, 则对一切a,都有a^p===a(mod p)。注意这里是一切a,即a和p不一定互素。

若p为素数,且p不能整除a(或能整除则结果为0),有\(a^n===a^{n\enspace mod(p-1)} \enspace(mod p)\)

欧拉降幂

[problem description]

\(a^b \enspace mod \enspace m (1\leq a\leq10^9,1\leq b\leq10^{20000000},1\leq m\leq10^8)\)

[solved]

\[\left.\left\{\begin{matrix}A^Bmod(C)=A^{Bmod(phi(C))}modC&(B<phi(C))\\A^Bmod(C)=A^{(Bmod(phi(C)))+phi(C)}modC&(B>=phi(C))\end{matrix}\right.\right. \]

ll a,b,m,phi;
bool flag;
string s;
int get_phi(int n){//求欧拉函数
  int res = n;
  for(int i=2; i*i<=n; i++){
    if(n%i == 0){
      res = res/i*(i-1);
      while(n%i == 0) n /= i;
    }
  }
  if(n>1) res = res/n*(n-1);
  return res;
}
int depow(ll phi){//降幂
  ll b = 0;
  int len=s.size();
    for(int i=0;i<len; i++){
      b = b*10+(s[i]-'0');
      if(b>=phi) flag=1, b%=phi;
    }
    if(flag) b += phi;
    return b;
}
int qmi(ll a, ll b){//快速幂
    int res = 1;
    while(b){
      if(b&1) res = res*a%m;
      a = a*a%m;
      b >>= 1;
    }
    return res;
}
void solve(){
	cin>>a>>m>>s;
    phi = get_phi(m);
    b = depow(phi);
    cout<<qmi(a,b)<<endl;
}

同余方程[\(\mathrm{ax\equiv b({\mathrm{mod}}\,m)}\)]

不定方程[\(ax+by=gcd(a,b)\)]

[solved]

扩展欧几里得算法实现

当b=0时,ax+by=a=>x=1,y=0

当b!=0时,gcd(a,b)=gcd(b,a%b)

[公式推导]

\[gcd(a,b)=ax+by\\gcd(b,a\%b)=bx_1+(a\%b)\\y_1=bx_1+(a-\left\lfloor\frac ab\right\rfloor\times b)y_1=ay_1+b(x_1-\frac aby_1) \]

所以\(x=y1,y=x1-\frac{a}{b}\times y1\)

可以通过递归算法,先求出下一层的\(x_1\)\(y1\),再回代到上一层,层层回代,可求特解\((x_0,y_0)\)

通解:

\[\begin{cases}x=x_0+\frac{b}{\gcd(a,b)}*k\\ y=y_0-\frac{a}{\gcd(a,b)}*k\end{cases} \]

ll exgcd(ll a,ll b,ll &x,ll &y){
  if(b == 0) {x=1, y=0; return a;}
  ll d = exgcd(b, a%b, y, x);
  y-=a/b*x;
  return d;
}
void solve(){
	ll a,b,c;
	cin>>a>>b>>c;
	ll x,y;
	ll d=exgcd(a,b,x,y);
	if(c%d==0) cout<<x<<" "<<y>>endl;//d|c才有整数解
	else cout<<"No"<<endl;
}

不定方程[\(ax+by=c\)]

[solved]

有整数解的充要条件:gcd(a,b)|c

ll exgcd(ll a,ll b,ll &x,ll &y){
  if(b == 0) {x=1, y=0; return a;}
  ll d = exgcd(b, a%b, y, x);
  y-=a/b*x;
  return d;
}
void solve(){
	ll a,b,c;
	cin>>a>>b>>c;
	ll x,y;
	ll d=exgcd(a,b,x,y);
	if(c%d==0) cout<<c/d*x<<" "<<c/d*y>>endl;//d|c才有整数解
	else cout<<"No"<<endl;
}

乘法逆元[\(\mathrm{ax\equiv 1({\mathrm{mod}}\, m)}\)]

求x的乘法逆元

若a,b不互素,则a必然不存在模b的逆元。

0没有乘法逆元

费马小定理

如果p是一个质数,而整数a不是p的倍数,则有a(p-1)===1(modp),则a*a(p-1)===1(modp)。

注意:乘法逆元不一定是存在的。a 存在乘法逆元的充要条件是 a 与模数 p 互质。当模数 p 为质数时,a^(p−2) 即为 a 的乘法逆元。

ll qmi(ll x,ll n,ll p){
	ll res=1;
	while(n){
		if(n&1) res=res*x%p;
		x=x*x%p;
		n>>=1;
	}
	return res;
}
ll gcd(ll x,ll y){
	return y?gcd(y,x%y):x;
}
void solve(){
	ll a,p;
	cin>>a>>p;
	if(gcd(a,p)==1) cout<<qmi(a,p-2,p)<<endl;
	else cout<<"impossible"<<endl;
}

扩展欧几里得

对于 modp 比较大的时候效率更好

拓欧求解 线性同余方程axc(mod b) 的c1的情况,可以转化为解ax+b*y=1这个方程。

当a与p互质,但p不是质数的时候也可以使用。

对于三个自然数a,b,c,求解ax+by=c的(x,y)的整数解。

首先我们要判断是否存在解,对于这个存在整数解的充分条件是 gcd(a,b) | c ,也就是说 c为 a,b 最大公因数的一个倍数。

【c++】

void exgcd(ll a,ll b, ll &x,ll &y){
	if(!b) x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll a,p;
void solve(){
	ll x,y;
	exgcd(a,p,x,y);
	x=(x%p+p)%p;
	cout<<x<<endl;
}

【python】

def exgcd(a, b):
    if b == 0:
        return a, 1, 0
    else:
        gcd, x1, y1 = exgcd(b, a % b)
        x = y1
        y = x1 - (a // b) * y1
        return gcd, x, y

线性求[1,n]的乘法逆元

1≤n≤3×10^6,n<p<20000528。

公式:\(\mathrm{inv[i]=((p-\lfloor\frac pi\rfloor)\times inv[p\%i])\%p}\)

int inv[3000010];
int n,p;
void solve(){
	cin>>n>>p;
	inv[1]=1;
	for(int i=2;i<=n;i++){
		inv[i]=((ll)p-p/i)*inv[p%i]%p;
	}
	for(int i=1;i<=n;i++) cout<<inv[i]<<endl;
}

线性求[1,n]的阶乘逆元

我们可以考虑用费马小定理先求出最大那个阶乘的逆元,然后再往回推。

逆元就可一看做是求倒数.

公式:\(\begin{aligned}\frac{1}{(n+1)!}\times(n+1)=\frac{1}{n!}\end{aligned}\)

const int N=1000010;
void init() {
	fact[0] = 1;
	for (int i = 1; i <N; i++) {
		fact[i] = fact[i - 1] * i %mod;
	}
	inv[N - 1] = power(fact[N- 1], mod - 2);
	for (int i = N-2; i >= 0; i--) {
		inv[i] = inv[i + 1] * (i + 1) %mod;
	}
}

模数两两互质的线性同余方程组(CRT)

[problem description]

设正整数\(m_1,m_2,...,m_k\)两两互素,则同余方程组:

\[\left\{\begin{array}{ll}\mathrm{x} \equiv \mathrm{a}_{1}(\bmod & \left.\mathrm{m}_{1}\right) \\ \mathrm{x} \equiv \mathrm{a}_{2}(\bmod & \left.\mathrm{m}_{2}\right) \\ \cdots \cdots & \\ \mathrm{x} \equiv \mathrm{a}_{\mathrm{k}}(\bmod & \left.\mathrm{m}_{\mathrm{k}}\right)\end{array}\right. \]

有整数解,并求x的最小非负整数解。

在模\(M = m 1 ∗ m 2 ∗ . . . ∗ m_k\)下的解是唯一的,解为:

\(\mathrm x\equiv(\mathrm a_1\mathrm c_1\mathrm c_1^{-1}+\mathrm a_2\mathrm c_2\mathrm c_2^{-1}+...+\mathrm a_k\mathrm c_k\mathrm c_k^{-1})\bmod M\)

[solved]

1.计算所有模数的积M

2.计算第i个方程的\(c_i=\dfrac{M}{m_i}\)

3.计算\(c_i\)在模\(m_i\)意义下的逆元\(c_i^{-1}\)(\(c_i\)的乘法逆元一定是存在的,因为在第2步以及把mi除去了,剩下的一定与mi互质)

4.\(x=\sum_{i=1}^{n}r_{i}c_{i}c_{i}^{-1}(modM)\)

const int N=110;
ll r[N];
ll m[N];
//扩展欧几里德
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	ll d=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return d;
}
void solve(){
	int n;
	cin>>n;
	ll M=1;
	for(int i=1;i<=n;i++){
		cin>>m[i]>>r[i];//m:模数,r:余数
		M*=m[i];
	}
	ll res=0;
	for(int i=1;i<=n;i++){
		ll c=M/m[i],x=0,y=0;
		ll c1=exgcd(c,m[i],x,y);
		res=(res+r[i]*c*x%M)%M;
	}
	cout<<(res%M+M)%M<<endl;
}

模数不一定两两互质的线性同余方程组(EXCRT)

[problem description]

设正整数\(m_1,m_2,...,m_k\)不一定两两互素,则同余方程组:

\[\left\{\begin{array}{ll}\mathrm{x} \equiv \mathrm{a}_{1}(\bmod & \left.\mathrm{m}_{1}\right) \\ \mathrm{x} \equiv \mathrm{a}_{2}(\bmod & \left.\mathrm{m}_{2}\right) \\ \cdots \cdots & \\ \mathrm{x} \equiv \mathrm{a}_{\mathrm{k}}(\bmod & \left.\mathrm{m}_{\mathrm{k}}\right)\end{array}\right. \]

如果有整数解,并求x的最小非负整数解。

[solved]

假设有一个有两个方程,我们将两个方程等价合并为一个方程\(\mathrm{x\equiv r(mod\quad m)}\)

其中\(r=m_1p+r_1\)\(m=lcm(m_1,m_2)\)

\[\begin{array}{rr}\mathrm{x\equiv r_1(mod}&\mathrm{m_1)}\\\mathrm{x\equiv r_2(mod}&\mathrm{m_2)}\end{array} \]

(1)将两个方程转化为不定方程:\(x=m_1p+r_1=m_2q+r_2\),则\(m_1p-m_2q=r_2-r_1\)

(2)求\(gcd(m_1,m_2)\)

\(\gcd(m_{1},m_{2})\nmid(r_{2}-r_{1})\)时,无解

\(\gcd(m_{1},m_{2})\mid(r_{2}-r_{1})\)时,有解

(3)通过扩欧算法求特解

特解:\(p=p*\frac{r_{2}-r_{1}}{gcd(m_1,m_2)}\)\(q=q*\frac{r_{2}-r_{1}}{gcd(m_1,m_2)}\)

通解:\(P=p+\frac{m_{2}}{gcd(m_1,m_2)}*k\)\(Q=q-\frac{m_{1}}{gcd(m_1,m_2)}*k\)

(4)合并方程

LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1,y=0; 
        return a;
    }
    LL d=exgcd(b,a%b,y,x);
    y -= (a/b) * x;
    return d;
}
LL EXCRT(LL m[],LL r[]){
    LL m1,m2,r1,r2,p,q;
    m1=m[1],r1=r[1];
    for(int i=2;i<=n;i++){
        m2=m[i],r2=r[i];
        LL d = exgcd(m1,m2,p,q);
        if((r2-r1)%d){
            return -1;
        }
        p=p*(r2-r1)/d;//特解
        p=(p%(m2/d)+m2/d)%(m2/d);//将p转化为最小的非负整数
        r1=m1*p+r1;
        m1=m1*m2/d;
    }
    return (r1%m1+m1)%m1;
}

分数取模

[problem desecription]

计算a/b%M

[solved]

费马小定理

[公式推导]

\[\begin{aligned}b^{M-1}modM&=1modM\\b^{M-2}modM&=b^{-1}modM\\a*b^{M-2}modM&=a*b^{-1}modM\\a/bmodM&=a*b^{M-2}modM\end{aligned} \]

const ll mod=1e9+7;
ll qmi(ll a,ll b){
    int res=1;
    while(b){
     if(b&1) res=res*a%mod;
     a=a*a%mod;
     b>>=1;
    }
    return res;
}
ll frac(ll a,ll b){
    return ((a%mod)*qmi(b,mod-2))%mod;
}

有理数取余

[problem description]

给出一个有理数c=a/b,求$cmod 19260817 $的值。

这个值被定义为\(bx≡a(mod19260817)\) 的解。

\(0≤a≤10^{10001}\)\(1≤b≤10^{10001}\),且 a,b 不同时是19260817 的倍数。

[solved]

b%mod*x==a%mod

当b%mod0时,(1)a%mod0时,x有无数解。(2)a%mod!=0时,x无解。

当a%mod!=0时,因为mod是质数,所以mod与b互质,这就满足了费马小定理的前提,所以根据费马小定理变形得必存在x使上述式子成立,即有解。

const int mod=19260817;
void read(int& x){
    int f=1;
    char ch;
    ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        x%=mod;
        ch=getchar();
    }
    x=x*f;
}
ll qmi(int a,int b){
 	ll res=1;
 	while(b){
  		if(b&1) res=res*a%mod;
  		a=(1ll)*a*a%mod;
  		b>>=1;
 	}
 	return res;
}
void solve(){
	int a=0,b=0;
 	read(a),read(b);
    if(b==0) {printf("Angry!\n");}
    else printf("%lld\n",(1ll)*a*qmi(b,mod-2)%mod);
}

可爱的质数

[problem description]

给定一个质数 \(p\),以及一个整数 \(a\),一个整数 \(b\),现在要求你计算一个最小的非负整数 \(x\),满足 \(a^x \equiv b \pmod p\)

[input]

仅一行,有 \(3\) 个整数,依次代表 \(p, a, b\)

[output]

仅一行,如果有 \(l\) 满足该要求,输出最小的 \(l\),否则输出 no solution

[datas]

\(2\le a,b < p<2^{31}\)

[solved]

BSGS算法求解高次同余方程的模板题

ll a,b,p;
ll res;
ll bsgs(ll a,ll b,ll p){
	a%=p;
	b%=p;
	if(b==1) return 0;
	ll m=ceil(sqrt(p));//向上取整
	ll t=b;
	unordered_map<int,int> up;
	up[b]=0;
	for(int j=1;j<m;j++){
		t=t*a%p;//求b*a^j
		up[t]=j;
	}
	ll x=1;
	for(int i=1;i<=m;i++)
		x=x*a%p;//求a^m
	t=1;
	for(int i=1;i<=m;i++){
		t=t*x%p;
		if(up.count(t)) return i*m-up[t];
	}
	return -1;
}
void solve() {
	cin>>p>>a>>b;
	res=bsgs(a,b,p);
	if(res==-1) cout<<"no solution"<<endl;
	else cout<<res<<endl;
}

扩展 BSGS

[problem description]

给定 \(a,p,b\),求满足 \(a^x≡b \pmod p\) 的最小自然数 \(x\)

[input]

每个测试文件中包含若干组测试数据,保证 \(\sum \sqrt p\le 5\times 10^6\)

每组数据中,每行包含 \(3\) 个正整数 \(a,p,b\)

\(a=p=b=0\) 时,表示测试数据读入完全。

[output]

对于每组数据,输出一行。

如果无解,输出 No Solution,否则输出最小自然数解。

[datas]

\(1\le a,p,b≤10^9\)\(a=p=b=0\)

[solved]

同余最短路

应用范围

给定 n个整数,求这n个整数能拼凑出多少的其他整数(n个整数可以重复取)

给定n个整数,求这 n 个整数不能拼凑出的最小(最大)的整数

至少要拼几次才能拼出模 K 余p 的数

同余最短路利用同余来构造一些状态,可以达到优化空间复杂度的目的。

类比 [差分约束]方法,利用同余构造的这些状态可以看作单源最短路中的点。同余最短路的状态转移通常是这样的 \(f(i+y)= f(i) + y)\),类似单源最短路中\(f(v)= f(u) +edge(u,v)\)

posted @ 2023-10-07 10:45  White_Sheep  阅读(44)  评论(0编辑  收藏  举报