*【学习笔记】(14) 初等数论(一)
1.【最大公约数(GCD)和最小公倍数(LCM)】
【基本性质、定理】
【推导结论】
-
且 -
且 -
-
在 斐波那契数列中求相邻两项的
时,辗转相减次数等于辗转相除次数。 -
证明
证明:
对于 显然成立。
手推一下发现 也成立
用数学归纳法,若 和 成立,那么 也成立:
结论3可以写作 ,然后用辗转相减法归纳一下就好了。
2.费马小定理
引理:当 是质数时,其因子只有 和 两个。因此,若两个数相乘是 的倍数,其中必然至少有一个是 的倍数。
当 不是 的倍数时,不存在 且 使得 。因为据引理, 是 的倍数,与 的限制矛盾。
进一步地,考虑
因此,
根据推导过程,它适用于
3.【裴蜀(Bézout)定理】
-
设
是不全为零的整数,则存在整数 , 使得 -
证明可以使用扩展欧几里得算法来证明
扩展欧几里得算法
扩展欧几里得算法简称扩欧或 exgcd。它是求解最大公约数的欧几里得算法的扩展,用于求解形如
1.1 解的存在性
先考虑一些较弱的结论。容易发现,无论
同时,我们注意到为
根据直观感受,对于
证明很容易,因为
证明:考虑
因为
综上,我们得到了判断二元线性不定方程
存在解的 充要条件:
显然裴蜀定理可以推广到
1.2 算法介绍
欲求解
注意到等式右端等于
exgcd 的核心思想与巧妙之处在于 递归构造。假设我们已经得到了
对比等式两端,有
递归边界即当
上述过程即扩展欧几里得算法,时间复杂度与辗转相除相同。代码如下。
void exgcd(int a, int b, int &x, int &y){ if(!b) return x = 1, y = 0, void(); exgcd(b, a % b, y, x), y -= a / b * x; }
【推导结论】
-
设不定方程
的一组特解为 ,则 的通解为 。 P5656 【模板】二元一次不定方程 (exgcd)
4.逆元
若
那逆元用来干什么呢?为了解决模意义下的除法问题,我们引入了逆元。inv(a) 其实可以看做模
求逆元常规有以下三种方法:
4.1 费马小定理求逆元
根据费马小定理
那么
4.2 扩展欧几里得求逆元
从这个方法中我们可以发现, a 存在逆元的冲要条件是
4.3 线性求逆元
- 如果我们要求
求 中所有整数在模 意义下的乘法逆元。
那么我们可以使用线性递推法。
假设 的逆元已求得,那么,设 ,即 。
- 如果我们要求任意 n 个数
的逆元,设 是 的前缀积,那么可以先用费马求出 ,然后通过 ,则 。
P3811 【模板】乘法逆元
5.欧拉函数
5.1 定义与性质
欧拉函数定义为在
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; } return n > 1 ? res / n * (n - 1) : res; }
线性筛欧拉函数
根据性质6
for(int i = 2; i <= 1e6; ++i){ if(!v[i]) p[++tot] = i, phi[i] = i - 1, v[i] = i; for(int j = 1; j <= tot && i * p[j] <= 1e6; ++j){ if(p[j] > v[i]) break; v[i * p[j]] = p[j]; phi[i * p[j]] = phi[i] * (i % p[j] ? p[j] - 1 : p[j]); } }
5.2 欧拉定理
SP5971 LCMSUM - LCM Sum
点击查看代码
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1e6 + 51; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } int T, n, tot; int ans[N], phi[N], p[N], v[N]; void solve(){ phi[1] = 1; for(int i = 2; i <= 1e6; ++i){ if(!v[i]) p[++tot] = i, phi[i] = i - 1, v[i] = i; for(int j = 1; j <= tot && i * p[j] <= 1e6; ++j){ if(p[j] > v[i]) break; v[i * p[j]] = p[j]; phi[i * p[j]] = phi[i] * (i % p[j] ? p[j] - 1 : p[j]); } } for(int i = 1; i <= 1e6; ++i) for(int j = 1; i * j <= 1e6; ++j) ans[i * j] += j * phi[j] / 2; for(int i = 1; i <= 1e6; ++i) ans[i] = i * ans[i] + i; } signed main(){ T = read(); solve(); while(T--){ n = read(); printf("%lld\n", ans[n]); } return 0; }
P4139 上帝与集合的正确用法
用欧拉定理缩指,发现一直递归下去
点击查看代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e7 + 51; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } int T, p, tot; int v[N], phi[N], pr[N]; void init(){ phi[1] = 1; for(int i = 2; i <= 1e7; ++i){ if(!v[i]) v[i] = i, phi[i] = i - 1, pr[++tot] = i; for(int j = 1; j <= tot && 1ll * pr[j] * i <= 1e7; ++j){ if(pr[j] > v[i]) break; v[i * pr[j]] = pr[j]; phi[i * pr[j]] = phi[i] * (i % pr[j] ? pr[j] - 1 : pr[j]); } } } ll qsm(ll a, ll b, ll mod){ int res = 1; for(; b; b >>= 1, a = (a * a) % mod) if(b & 1) res = (res * a) % mod; return res; } ll solve(int mod){ if(mod == 1) return 0; return qsm(2, solve(phi[mod]) + phi[mod], mod); } int main(){ init(); T = read(); while(T--){ p = read(); printf("%lld\n", solve(p)); } return 0; }
P3747 [六省联考 2017] 相逢是问候
和上题类似,使用光速幂。
点击查看代码
#include<bits/stdc++.h> #define ll long long #define ls u << 1 #define rs u << 1 | 1 using namespace std; const int N = 5e4 + 51, D = 60; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } int n, m, P, c, cntp; int p[D]; int a[N][D], minn[N << 2]; ll sum[N << 2], c1[D][1 << 15], c2[D][1 << 15]; int phi(int x){ int ans = x; for(int i = 2; i * i <= x; ++i){ if(x % i) continue; while(x % i == 0) x /= i; ans = ans / i * (i - 1); } if(x > 1) ans = ans / x * (x - 1); return ans; } int mod(ll n, int p){ return n >= p ? (n % p + p) : n; } void init(){ for(int i = 0; i <= cntp; ++i){ c1[i][0] = c2[i][0] = 1; for(int j = 1; j < 1 << 15; ++j) c1[i][j] = mod((ll) c1[i][j - 1] * c, p[i]); c2[i][1] = mod(c1[i][(1 << 15) - 1] * c, p[i]); for(int j = 2; j < 1 << 15; ++j) c2[i][j] = mod((ll) c2[i][j - 1] * c2[i][1], p[i]); } } int csm(int n, int i){ return mod((ll) c1[i][n % (1 << 15)] * c2[i][n >> 15], p[i]); } int solve(int x, int cnt, int i){ if(!cnt) return mod(x, p[i]); if(i == cntp) return 1; return csm(solve(x, cnt - 1, i + 1), i); } void PushUp(int u){ minn[u] = min(minn[ls], minn[rs]); sum[u] = (sum[ls] + sum[rs]) % P; } void Build(int u, int l, int r){ if(l == r) return minn[u] = 0, sum[u] = a[l][0], void(); int mid = (l + r) >> 1; Build(ls, l, mid), Build(rs, mid + 1, r); PushUp(u); } void UpDate(int u, int l, int r, int L, int R){ if(minn[u] > cntp) return ; if(l == r) return ++minn[u], sum[u] = a[l][minn[u]], void(); int mid = (l + r) >> 1; if(L <= mid) UpDate(ls, l, mid, L, R); if(R > mid) UpDate(rs, mid + 1, r, L, R); PushUp(u); } int Query(int u, int l, int r, int L, int R){ if(L <= l && r <= R) return sum[u]; int mid = (l + r) >> 1; ll ans = 0; if(L <= mid) ans = (ans + Query(ls, l, mid, L, R)) % P; if(R > mid) ans = (ans + Query(rs, mid + 1, r, L, R)) % P; return ans; } int main(){ n = read(), m = read(), P = read(), c = read(); p[cntp = 0] = P; while(p[cntp] > 1) ++cntp, p[cntp] = phi(p[cntp - 1]); init(); for(int i = 1; i <= n; ++i){ a[i][0] = read(); for(int j = 1; j <= cntp + 1; ++j) a[i][j] = solve(a[i][0], j, 0) % P; a[i][0] %= P; } Build(1, 1, n); while(m--){ int opt = read(), l = read(), r = read(); if(opt == 0) UpDate(1, 1, n, l, r); else printf("%d\n", Query(1, 1, n, l, r)); } return 0; }
6.离散对数问题
6.1 大步小步算法
int BSGS(int a, int b, int p){ int A = 1, B = sqrt(p) + 1; a %= p, b %= p; gp_hash_table <int, int> mp; mp[b] = 0; for(int i = 1; i <= B; ++i) mp[(A = A * a % p) * b % p] = i; for(int i = 1, AA = A; i <= B; ++i, AA = AA * A % p) if(mp.find(AA) != mp.end()) return i * B - mp[AA]; return -1; }
容易发现 BSGS 求得的是
6.2 扩展大步小步算法
P3846 [TJOI2007] 可爱的质数/【模板】BSGS
BSGS模板题。
点击查看代码
#include<bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #define int long long using namespace std; using namespace __gnu_pbds; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();} return x * f; } int p, b, m; int BSGS(int a, int b, int p){ int A = 1, B = sqrt(p) + 1; a %= p, b %= p; gp_hash_table <int, int> mp; mp[b] = 0; for(int i = 1; i <= B; ++i) mp[(A = A * a % p) * b % p] = i; for(int i = 1, AA = A; i <= B; ++i, AA = AA * A % p) if(mp.find(AA) != mp.end()) return i * B - mp[AA]; return -1; } signed main(){ p = read(), b = read(), m = read(); int ans = BSGS(b, m, p); if(~ans) printf("%d\n", ans); else printf("no solution\n"); return 0; }
P4195 【模板】扩展 BSGS/exBSGS
exBSGS模板题
点击查看代码
#include<bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #define int long long using namespace std; using namespace __gnu_pbds; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();} return x * f; } int a, b, p; int BSGS(int a, int b, int p){ int A = 1, B = sqrt(p) + 1; a %= p, b %= p; gp_hash_table <int, int> mp; mp[b] = 0; for(int i = 1; i <= B; ++i) mp[(A = A * a % p) * b % p] = i; for(int i = 1, AA = A; i <= B; ++i, AA = AA * A % p) if(mp.find(AA) != mp.end()) return i * B - mp[AA]; return -1; } void exgcd(int a, int b, int &x, int &y){ if(!b) return x = 1, y = 0, void(); exgcd(b, a % b, y, x), y -= a / b * x; } int inv(int x, int p){ return exgcd(x, p, x, *new int), (x % p + p) % p; } int exBSGS(int a, int b, int p){ int d = __gcd(a, p), cnt = 0; a %= p, b %= p; while(d > 1){ if(b == 1) return cnt; if(b % d) return -1; p /= d, b = b / d * inv(a / d, p) % p; d = __gcd(p, a %= p), ++cnt; } int ans = BSGS(a, b, p); return ~ans ? ans + cnt : -1; } signed main(){ while(1){ a = read(), p = read(), b = read(); if(!p) break; int ans = exBSGS(a, b, p); if(~ans) printf("%d\n", ans); else printf("No Solution\n"); } return 0; }
7.线性同余方程组
7.1 中国剩余定理
7.2 扩展中国剩余定理
P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪
点击查看代码
#include<bits/stdc++.h> #define N 15 #define int long long using namespace std; int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,M=1,X; int a[N],b[N],m[N]; void exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1,y=0; return ; } exgcd(b,a%b,y,x); y-=(a/b)*x; } signed main(){ n=read(); for(int i=1;i<=n;i++){ a[i]=read(),b[i]=read(); M*=a[i]; } for(int i=1;i<=n;i++){ m[i]=M/a[i]; int x=0,y=0; exgcd(m[i],a[i],x,y); X+=b[i]*m[i]*((x%a[i]+a[i])%a[i]); } printf("%lld\n",X%M); return 0; }
P4777 【模板】扩展中国剩余定理(EXCRT)
点击查看代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e5 + 51; ll read(){ ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } ll n, a, b, c, d; void exgcd(ll a, ll b, ll &x, ll &y){ if(!b) return x = 1, y = 0, void(); exgcd(b, a % b, y, x), y -= a / b * x; } int main(){ n = read(), a = read(), b = read(); for(int i = 1; i < n; ++i){ c = read(), d = read(); ll e = __gcd(a, c), f = (d - b % c + c) % c, inv; c /= e, f /= e; exgcd(a / e, c, inv, *new long long), inv = (inv % c + c) %c; b += (__int128) f * inv % c * a, a *= c, b %= a; } printf("%lld\n", b); return 0; }
8.高斯消元法
8.1过程
首先要把方程转化为增广矩阵
模板 P3389 【模板】高斯消元法
高斯消元
首先找到一个第一列的数不为0的行(一般找第一列的数最大的行)(如果都为0就跳过当前步)
然后用它的第一列的数将下面行当前列的值化为0,变换过的初等矩阵与原矩阵等价,化为方程后依然成立
本矩阵第一列的数最大的为第三行就把第三行与第一行交换
然后将下面行的当前列消去,如图
最后得到上三角矩阵如图
这样可以解出
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pii pair<int, int> #define ls u << 1 #define rs u << 1 | 1 #define eps 1e-7 #define db double using namespace std; const int N = 1e2 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n; db a[N][N], ans[N]; int solve(int n){ int r, c = 1; for(r = 1; r <= n && c <= n; ++r, ++c){ int maxn = r; for(int i = r; i <= n; ++i) if(fabs(a[i][c]) > fabs(a[maxn][c])) maxn = i; if(maxn != r) swap(a[r], a[maxn]); if(fabs(a[r][c]) < eps){--r; continue;} for(int i = r + 1; i <= n; ++i){ if(fabs(a[i][c]) > eps){ db tmp = a[i][c] / a[r][c]; for(int j = c; j <= n + 1; ++j) a[i][j] -= a[r][j] * tmp; a[i][c] = 0; } } } for(int i = r; i <= n; ++i) if(fabs(a[i][c]) > eps) return -1; if(r <= n) return n - r + 1; for(int i = n; i; --i){ for(int j = i + 1; j <= n; ++j) a[i][n + 1] -= a[i][j] * ans[j]; ans[i] = a[i][n + 1] / a[i][i]; } return 0; } bool _v; int main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; n = read(); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n + 1; ++j) scanf("%lf", &a[i][j]); int flag = solve(n); if(flag != 0) printf("No Solution\n"); else for(int i = 1; i <= n; ++i) printf("%.2lf\n", ans[i]); return 0; }
高斯约旦消元
同高斯消元大体差不多,但消元时上面计算过的行也要消去当前列,最后得到的是对角矩阵而不是上三角矩阵。
第一次和高斯消元相同
然后第二次要将第一行的也消去
最后得到的如图
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pii pair<int, int> #define ls u << 1 #define rs u << 1 | 1 #define eps 1e-7 #define db double using namespace std; const int N = 1e2 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n; db a[N][N]; bool _v; int main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; n = read(); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n + 1; ++j) scanf("%lf", &a[i][j]); for(int i = 1; i <= n; ++i){ int r = i; for(int j = i + 1; j <= n; ++j) if(fabs(a[j][i]) > fabs(a[r][i])) r = j; if(fabs(a[r][i]) < eps) printf("No Solution\n"), exit(0); for(int j = 1; j <= n + 1; ++j) swap(a[i][j], a[r][j]); for(int j = 1; j <= n; ++j){ if(j == i) continue; db tmp = a[j][i] / a[i][i]; for(int k = i + 1; k <= n + 1; ++k) a[j][k] -= a[i][k] * tmp; } } for(int i = 1; i <= n; ++i) printf("%.2lf\n", a[i][n + 1] / a[i][i]); return 0; }
P4035 [JSOI2008] 球形空间产生器
一个球体上的所有点到球心距离相等,因此我们只需求出一个点(
其中C为常数,
改方程组由
我们可以通过相邻两个方程做差,变成
有点像数学中数列求通项公式或者前
于是有:
把变量放左边,常数放右边:
so,我们要对这个增广矩阵进行高斯消元:
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pii pair<int, int> #define ls u << 1 #define rs u << 1 | 1 #define eps 1e-7 #define db double using namespace std; const int N = 1e2 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n; db b[N][N]; db a[N][N]; bool _v; int main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; n = read(); for(int i = 1; i <= n + 1; ++i) for(int j = 1; j <= n; ++j) scanf("%lf", &b[i][j]); for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ a[i][j] = 2 * (b[i][j] - b[i + 1][j]); a[i][n + 1] += b[i][j] * b[i][j] - b[i + 1][j] * b[i + 1][j]; } } for(int i = 1; i <= n; ++i){ int r = i; for(int j = i + 1; j <= n; ++j) if(fabs(a[j][i]) > fabs(a[r][i])) r = j; for(int j = 1; j <= n + 1; ++j) swap(a[i][j], a[r][j]); for(int j = 1; j <= n; ++j){ if(j == i) continue; db tmp = a[j][i] / a[i][i]; for(int k = i + 1; k <= n + 1; ++k) a[j][k] -= a[i][k] * tmp; } } for(int i = 1; i <= n; ++i) printf("%.3lf ", a[i][n + 1] / a[i][i]); return 0; }
8.2 比较
约旦法精度更好、代码更简单,没有回带的过程。
但约旦法无法分辨 无解 与 无唯一解 的情况。
对于高斯消元法:
-
如果有一行方程的所有变量的系数都为0,而常数项不为0,方程当然就无解啦。
-
如果有一行方程的所有变量的系数都为0,常数项也为0,那么这就说明出现了自由元(就是在这个方程中不受约束可以自由取值的未知数),且自由元的个数=全部为0的行数,这样就会导致方程多解了。
8.3 应用
8.3.1 解异或方程组
对于一个灯只有按或者不按两种状态,如果按也只会按一次,最终我们希望所有的灯的状态都为
即解这
类似于高斯消元解线性方程组,我们同样要将 一些系数消为 0 。发现系数
考虑高斯消元的过程,因为我们选取的那一行的那一列的系数必然为
举个例子:
得:
所以把减消元改为异或消元即可。
对于这道题,因为有自由元(即不确定的 x) ,我们需要 dfs 选取最优解。
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pii pair<int, int> #define ls u << 1 #define rs u << 1 | 1 #define eps 1e-7 #define db double using namespace std; const int N = 1e2 + 67; int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();} return x * f; } bool _u; int n, m, ans = 67; int a[N][N], l[N]; int solve(int n){ bool flag = 1; for(int i = 1; i <= n; ++i){ int r = i; for(int j = i + 1; j <= n; ++j) if(a[j][i] > a[r][i]) r = j; if(!a[r][i]){flag = 0; continue;} swap(a[i], a[r]); for(int j = 1; j <= n; ++j){ if(i == j || !a[j][i]) continue; for(int k = i; k <= n + 1; ++k) a[j][k] ^= a[i][k]; } } return flag; } void dfs(int x, int num){ if(num >= ans) return ; if(x == 0) return ans = num, void(); if(a[x][x]){ bool v = a[x][n + 1]; for(int i = x + 1; i <= n; ++i) if(a[x][i]) v ^= l[i]; dfs(x - 1, num += (l[x] = v)); }else{ l[x] = 0, dfs(x - 1, num); l[x] = 1, dfs(x - 1, num + 1); } } bool _v; int main(){ cerr << abs(&_u - &_v) / 1048576.0 << " MB\n"; n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i][i] = 1, a[i][n + 1] = 1; for(int i = 1, x, y; i <= m; ++i) x = read(), y = read(), a[x][y] = a[y][x] = 1; int flag = solve(n); if(flag){ int res = 0; for(int i = 1; i <= n; ++i) res += a[i][n + 1]; printf("%d\n", res); }else dfs(n, 0), printf("%d\n", ans); return 0; }
参考:
https://mzwuzad.blog.luogu.org/noip-2017-xiao-kai-di-ni-huo
https://www.cnblogs.com/alex-wei/p/Number_Theory.html
https://www.cnblogs.com/Xing-Ling/p/11990652.html
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17417678.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步