2023-10-07 10:45阅读: 88评论: 0推荐: 0

余数定理学习指南

前置芝士

乘法逆元

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,则 ari+b(i[0,n1])也构成一个模 n 的完全剩余系。

简化剩余系

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

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

[性质1]

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

[证明]

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

因为φ(n)是固定不变的,只要通过反证法证明ax1,ax2,,axϕ(m)ϕ(m)个数模m两两不同余即可。若存在xixj,i!=j,使得axiaxj(modm)

若上面等式成立,需要满足m|a(xixj),由于gcd(a,m)=1,所以xixj(modm),这与x1,x2,,xϕ(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

但万幸的是,若b0,扩展欧几里得算法求出的可行解必有|x|b,|y|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互质的数的数目。

公式:ϕ(x)=x(11p1)(11p2)(11pn),其中 p1,p2pn 是 x 的所有质因数。

[性质]

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

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

当n根据算术基本定理分解为n=p1c1p2c2pmcm时,ϕ(n)=i=1mϕ(pici)

【证明】

若n与m互质,则n与m没有相同的质因子设n的质因子个数为cntn,m的质因子个数为cntm,则

ϕ(n)ϕ(m)=ni=1cntn(1pi)mi=1cntm(1pi)=nmi=1cntn+cntm(1pi)=ϕ(nm)

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

[证明]

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

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

[证明]

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

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

(4)n=pk,ϕ(n)=pkpk1

(5)n中与n互质的数的和为ϕ(n)÷2×n(n>1),并且ϕ(n)(n>2)为偶数。

(6)p|np2|n,则ϕ(n)=ϕ(np)pp|np2n,ϕ(n)=ϕ(np)(p1)

(7)d|nϕ(d)=n

(8)ϕ(n)=d|nμ(d)d

欧拉定理

[定义]

gcd(a,m)=1,则 aφ(m)1 (mod m)

费马小定理ap11 ( mod p),其中gcd(a,p)=1,是欧拉定理的一种特性。

[证明]

。。。。。。

扩展欧拉定理

[公式]

ab{abmodφ(m),gcd(a,m)=1,ab,gcd(a,m)1,b<φ(m),(mod m)a(bmodφ(m))+φ(m),gcd(a,m)1,bφ(m).

[证明]

。。。。。。

快速幂

递归方式:log(n)

【思路分析】

xn: ①若n为偶数,xn=xn/2xn/2x(n/2)2; ②若n为奇数,xn=xn/2xn/2x

//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)

【思路分析】

x11: 11的二进制:1011,于是x11=x(20+21+23)=x(20)x(21)x(23)x=xx2x8, 只要分别求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

231<=n<=2311

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,满足 axb(modp)

Baby Step Giant Step

(1)由扩展欧拉定理axaxmodφ(p)(modp),可知ax模p意义下的最小循环节为φ(p),因φ(p)<p,故考虑x[0,p],必能找到最小整数x。

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

(3)令x=imj,其中m=p,i[1,m],j[0,m1]

aimjb(modp),转化为(am)ibaj(modp)

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

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

扩展BSGS算法

给定 a,p,b,求满足 axb(modp) 的最小自然数 x

[解题步骤]

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

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

(3)原方程等价于aax1+py=b

d1=gcd(a,p)d1b,则原方程无解。

否则方程两边同时除于d1,得ad1ax1bd1(modpd1)

如果a和pd1仍不互质再除

d2=gcd(a,pd1)d2bd1,则原方程无解。

或者方程两边需要同时除于d2,得a2d1d2ax2bd1d2(modpd1d2)

不停的判断下去,直到apd1dk,记D=i=1kdi

原方程变为akDaxkbD(modpD)

apD,则akDpD,则akD就有逆元了,把它丢到方程右边,就是一个标准的BSGS问题了,求解出x-k后再加上k就ok了。

akDaxkbD(modpD)=Aaimjb(modp)

求解正整数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不互质的数的个数。

(1lr1012,rl106)

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),有an===anmod(p1)(modp)

欧拉降幂

[problem description]

abmodm(1a109,1b1020000000,1m108)

[solved]

{ABmod(C)=ABmod(phi(C))modC(B<phi(C))ABmod(C)=A(Bmod(phi(C)))+phi(C)modC(B>=phi(C))

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;
}

同余方程[axb(modm)]

不定方程[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+bygcd(b,a%b)=bx1+(a%b)y1=bx1+(aab×b)y1=ay1+b(x1aby1)

所以x=y1,y=x1ab×y1

可以通过递归算法,先求出下一层的x1y1,再回代到上一层,层层回代,可求特解(x0,y0)

通解:

{x=x0+bgcd(a,b)ky=y0agcd(a,b)k

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;
}

乘法逆元[ax1(modm)]

求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。

公式:inv[i]=((ppi)×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]的阶乘逆元

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

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

公式:1(n+1)!×(n+1)=1n!

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]

设正整数m1,m2,...,mk两两互素,则同余方程组:

{xa1(modm1)xa2(modm2)xak(modmk)

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

在模M=m1m2...mk下的解是唯一的,解为:

x(a1c1c11+a2c2c21+...+akckck1)modM

[solved]

1.计算所有模数的积M

2.计算第i个方程的ci=Mmi

3.计算ci在模mi意义下的逆元ci1(ci的乘法逆元一定是存在的,因为在第2步以及把mi除去了,剩下的一定与mi互质)

4.x=i=1nricici1(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]

设正整数m1,m2,...,mk不一定两两互素,则同余方程组:

{xa1(modm1)xa2(modm2)xak(modmk)

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

[solved]

假设有一个有两个方程,我们将两个方程等价合并为一个方程xr(modm)

其中r=m1p+r1m=lcm(m1,m2)

xr1(modm1)xr2(modm2)

(1)将两个方程转化为不定方程:x=m1p+r1=m2q+r2,则m1pm2q=r2r1

(2)求gcd(m1,m2)

gcd(m1,m2)(r2r1)时,无解

gcd(m1,m2)(r2r1)时,有解

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

特解:p=pr2r1gcd(m1,m2)q=qr2r1gcd(m1,m2)

通解:P=p+m2gcd(m1,m2)kQ=qm1gcd(m1,m2)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]

费马小定理

[公式推导]

bM1modM=1modMbM2modM=b1modMabM2modM=ab1modMa/bmodM=abM2modM

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,求cmod19260817的值。

这个值被定义为bxa(mod19260817) 的解。

0a10100011b1010001,且 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,满足 axb(modp)

[input]

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

[output]

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

[datas]

2a,b<p<231

[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,求满足 axb(modp) 的最小自然数 x

[input]

每个测试文件中包含若干组测试数据,保证 p5×106

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

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

[output]

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

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

[datas]

1a,p,b109a=p=b=0

[solved]

同余最短路

应用范围

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

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

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

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

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

本文作者:White_Sheep

本文链接:https://www.cnblogs.com/taotao123456/p/17745782.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   White_Sheep  阅读(88)  评论(0编辑  收藏  举报
(评论功能已被禁用)
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑