容斥与反演
容斥与反演
前言:笔者写的东西大都是带有强烈主观思想的实验性笔记,并不适合 OI 食用。可以选择只读练习题。
容斥原理
容斥原理
设全集
为了方便表述,下文将
容斥原理:
其中
证明:考察每个容斥素的贡献系数是否均为
每个容斥素的贡献系数均为
集合的交可以用全集减去补集的并集计算:
广义容斥原理
记
注意
容斥原理通过计算
首先有:
更好的计算方式是:
证明:考察是否只有恰好满足
考察一个恰好满足
-
:没有被计算过。 -
:只有当 时有 份贡献。 -
:直接写出贡献式:
因此广义容斥原理成立。
这是经典容斥原理利用德摩根定律的结果。
附:德摩根定律:
P3813 [FJOI2017] 矩阵填数
Problem
给定一个
给这个矩阵填数的时候有一些限制,给定
现在,你的任务是求出有多少种填数的方案满足
由于答案可能很大,你只需要输出答案对
Solution
记容斥全集为
定义此处
进行容斥:
然而还是不好算:|原因在于
不妨在最开始就避免后者,即定义一个填数状态必须满足每个位置不超过在该位置的所有限制的最小值。
这样
反射容斥
之前 lh 的模拟赛中 T1 放了一道全场最难的反射容斥,直接把我创似了。
这一节与前后文关系不大,可以选择跳过。或者说是笔者还没有找到它与经典容斥的联系:|
首先,你需要知道如何用网格图推导卡特兰数的通项公式,这个你随便一搜就出来了,然后你领悟的一个重要思想,叫做 翻折终点,这就是反射容斥的 反射。
然后你就会单侧反射容斥了,所以我们接下来只讨论双限制的反射容斥。
问题:给定
与 ( ),求从 向右或向上移动到 且不碰线的方案数。
我们可以用一串字符序列表示经过两条线的情况,如果多次经过一条线,等价于经过一次(都只会翻折一次),因此把连续相同字符合并,表示 “由哪条线进行翻折” 的序列。
接下来使用二元容斥。
设容斥全集为
这里并没有使用经典容斥原理,而是具体问题具体分析,得到以下结论:
这个结论太优美了,它如此生动清晰。如果非要给它一个证明:
首先要承认事实:
下证
所以
有了这个结论就好办了。由经典容斥原理,
最后来分析一下求解上式的复杂度。
笔者尝试用经典容斥直接统一反射容斥,未果,但好在得到了以上解释反射容斥原理的一个思路。
反射容斥真的太独特了,它的独特是集合反演、二项式反演等无法比及的。或许反射容斥注定与经典容斥属于不同的道路?这是笔者仍在思考的地方。
2023.11.16T1
Problem
小薰和公生制作了
如果一个排列的任意的一个区间
然而制作出来的琴键的原排列并不一定「优美」,小薰和公生决定对它们重新排列,我发现你愿意帮助他们,请数出他们可以组装多少种不同的「优美」的钢琴,由于答案规模较大,请输出答案对
Solution
考虑前缀和:把白键视作
考虑网格图模型:初始在
要求
考虑到一个
假设
这里给出一个实现。
// Sea, You & Me
const int N = 2e7 + 5;
int fac[N], facinv[N];
void preprocess()
{
fac[0] = facinv[0] = 1;
for(int i = 1; i < N; ++i)
fac[i] = mul(fac[i - 1], i);
facinv[N - 1] = qwqmi(fac[N - 1]);
for(int i = N - 2; i >= 1; --i)
facinv[i] = mul(facinv[i + 1], i + 1);
}
int C(int n, int m)
{
if(n < 0 || m < 0 || n < m) return 0;
return mul(fac[n], mul(facinv[m], facinv[n - m]));
}
int f(int n, int m)
{
if(n < 0 || m < 0) return 0;
return C(n + m, n);
}
PII sym(PII p, int b)
{
return MP(p.se - b, p.fi + b);
}
int dfs(PII p, int a, int b)
{
if(p.fi < 0 || p.se < 0) return 0;
return dec(f(p.fi, p.se), dfs(sym(p, a), b, a));
}
int calc(int n, int m, int k)
{
int res = 0;
for(int i = 0; i >= -k; --i)
{
if(n + i > m || n + i + k < m) continue;
Inc(res, f(n, m));
Dec(res, dfs(sym(MP(n, m), i - 1), i + k + 1, i - 1));
Dec(res, dfs(sym(MP(n, m), i + k + 1), i - 1, i + k + 1));
}
return res;
}
int n, m, k;
int main()
{
preprocess();
read(n), read(m), read(k);
if(abs(n - m) > k || k == 0) return puts("0"), 0;
if(k >= max(n, m)) return printf("%d\n", f(n, m)), 0;
printf("%d\n", dec(calc(n, m, k), calc(n, m, k - 1)));
return 0;
}
/* sample 1
2 2 1
ans : 2
*/
/* sample 2
19 12 2
ans : 0
*/
/* sample 3
11 14 4
ans : 485072
*/
/* sample 4
133 128 20
ans : 170238429
*/
/* sample 5
11451 11450 2
ans : 199761117
*/
/* sample 6
1926081 9999999 9982443
ans : 785189997
*/
P3266 [JLOI2015] 骗我呢
Problem
求满足以下限制的
。 ,有 。 ,有 。
Solution
一个很好的性质是:每行只会有一个数值不会出现。
因此可以设计
把和式消掉:
注意当
初始化:
我们对
接下来的数形结合厉害了!
下面是一个
做完了。
集合反演
这里对第一个式子给出证明。
充分性:
特判当
否则当
必要性:
然后施以同样的分析,只有当
第二个式子推法相同,不再赘述。
对于容斥问题的意义:第一个式子给出了 至少 与 恰好 的转换,第二个式子给出了 至多 与 恰好 的转换。
需要指出,我只是证明了集合反演的正确性,这是非常 naive 的。等到笔者有能力明白集合反演更本质的东西时,会补充它的来由。
至于 OI-wiki 把它称作 ”容斥原理的一般化“,笔者实在是无法理解,甚至认为应该叫做 ”特殊化“ 才对。
P3349 [ZJOI2016] 小星星
Problem
给出一张图
Solution
首先有一个显然的状压 DP:记
把集合的限制提出来做
记
记
显然有
集合
答案为:
笔者憨了,因为显然可以直接进行
但这也指出了一种运用集合反演的视角,即通过 进行贡献系数与容斥系数的转换 解决问题。
集合反演与容斥的关系
在本例中,我们令容斥全集为
定义此处
我们用经典容斥式进行推导:
我们得到了相同的结果。
容斥问题中经常会出现 至多、至少 与 恰好 的转换,在容斥原理上结合具体情形可以直观地看到转换过程,但其缺点在于过程相对繁琐,而且初学时容易混淆集合的带权问题。
而集合反演指出了一类关于集合容斥的形式化解决方法,使得过程更为简单。
这里 “集合容斥“ 的意义其实就是 把集合作为容斥素,把集合内的元素作为容斥属性。
反演在容斥中体现在凑和式从
gossip:也许一年前的我即使没有系统地学这些东西也能说出一个「显然」的容斥做法,而我现在明白了这种做法的「本质」。可我又到哪里寻求「显然」的「本质」呢?
[AGC005D] ~K Perm Counting
Problem
如果一个排列
输出答案对
Solution
上例展现的是子集反演,此例展现了超集反演。
记
记
显然有
注意到对于大小均为
因此可以记
将
该图的一个匹配与钦定的排列形成双射!边数为
一种 naive 的思路是,对每条链做一个 DP,然后再进行背包合并。事实上,可以直接将所有链合并成一条链做一遍 DP 即可,不过要特殊判断不能选一条链的终点和另一条链的起点相连的边。时间复杂度
事实上,一条长为
另一个观察是:只有两种长度不同的链,因此可以直接启动多项式快速幂。
Bonus:用二项式反演推导本题,并思考集合反演与二项式反演的联系与区别。
P5644 [PKUWC2018] 猎人杀
Problem
一开始有
然而向谁开枪也是有讲究的,假设当前还活着的猎人有
一开始第一枪由你打响,目标的选择方法和猎人一样(即有
由于开枪导致的连锁反应,所有猎人最终都会死亡,现在
答案对
Solution
记全集为
首先,由于猎人似掉的概率时刻在变化,这不方便我们分析,因此要对问题进行转化。
原问题等价于:可以向尸体开枪,则猎人
证明:假设当前活着的人集合为
在新的模型中,其被击杀的概率为
记
记
注意
显然有
考虑
从集合的角度很难继续考虑问题了,注意到
这是喜闻乐见的分治 + NTT,时间复杂度两只老哥。
P5405 [CTS2019] 氪金手游
Problem
设第一次抽到
Solution
首先考虑外向树:记
于是可以记
对于存在反向边的情况,考虑用 无限制 减去 正向边(将反向边反向) 进行计算。
记反向边集合为全集
设
设
思考
具体地,记
初始化:
考虑
若限制为
若限制为
遍历完
启发:连续四道(包括下面这道神题)都是相同的超集反演的形式。在答案只需求空集权值的情况下,反演对象可以设计得非常大胆,而这也是最值得思考的一部分。
P9563 [SDCPC2023] Be Careful 2
Problem
小青鱼有一个位于二维平面上的,大小为
矩形内部有
请计算小青鱼可以画的正方形的总面积对
Solution
有眼不识泰山,我把这题想得太简单了。
记
记
所以答案为
枚举
想知道包含点集
为了方便表述,我们称去除实际矩形的最外层后留下的图案称为简化矩形(这个图案可能不是矩形)。
记
思考后面那坨容斥系数之和如何计算时,发现还可以继续优化:如果一个点不在简化矩形边界上,该矩形贡献为
也就是说,只有所有点都在边界上的简化矩形是有贡献的。考虑枚举左右边界上的点,则上下边界各
for(int i = 1; i <= K; ++i)
{
int U = INF, D = -INF;
a[++cnt] = Rec(p[i].fi, p[i].fi, p[i].se, p[i].se);
for(int j = i + 1; j <= K; ++j)
{
if(p[j].se >= U || p[j].se <= D) continue;
int mn = min(p[i].se, p[j].se);
int mx = max(p[i].se, p[j].se);
a[++cnt] = Rec(p[i].fi, p[j].fi, mx, mn);
a[++cnt] = Rec(p[i].fi, p[j].fi, mx, D);
a[++cnt] = Rec(p[i].fi, p[j].fi, U, mn);
a[++cnt] = Rec(p[i].fi, p[j].fi, U, D);
if(p[j].se >= p[i].se) U = p[j].se;
if(p[j].se <= p[i].se) D = p[j].se;
}
}
sort(a + 1, a + cnt + 1);
cnt = unique(a + 1, a + cnt + 1) - (a + 1);
枚举出所有简化矩形后,分类讨论不同形态的贡献系数:
-
一个点:
。 -
一条线:
- 仅两个端点上存在禁止点:
。 : 。
- 仅两个端点上存在禁止点:
-
是一个正规矩形:
以下称边上的禁止点时,不包含角上的禁止点。
- 四个角上没有禁止点:
。 - 一个角上有禁止点:
- 不选这个角:若每条边上有禁止点,贡献
,否则为 。 - 选这个角:若角的相邻两边有禁止点,贡献
,否则为 。
- 不选这个角:若每条边上有禁止点,贡献
- 两个相邻角上有禁止点:
- 不选角:同上。
- 选一个角:若与被选角相邻的两边上有禁止点,贡献为
;若另外两边上没有禁止点,贡献为 ;否则为 。 - 选两个角:若与角相邻的三边上有禁止点,贡献为
;否则为 。
- 两个对角上有禁止点:
- 不选角:同上。
- 选一个角:同上。
- 选两个角:若存在一边有禁止点,贡献为
,否则为 。
- 三个角上有禁止点:
- 不选角:同上。
- 选一个角:同上。
- 选两个邻角:若与被选角相邻的三边上有禁止点,贡献为
;若另外一边上没有禁止点,贡献为 ;否则为 。 - 选两个对角:若存在一边有禁止点,贡献为
,否则为 。 - 选三个角:若存在一边有禁止点,贡献为
,否则为 。
- 四个角均有禁止点:
- 不选角:同上。
- 选一个角:同上。
- 选两个邻角:同上。
- 选两个对角:同上。
- 选三个角:同上。
- 选四个角:若存在一边有禁止点,贡献为
,否则为 。
- 四个角上没有禁止点:
以上均可用二项式定理推出。
这太难绷了!而且实现会带上一只老哥。笔者尝试实现,发现其在极端数据下要跑将近 20 秒,还有空间爆炸的危险,无法通过。
int calc_coef(int l, int r, int u, int d)
{
PII w = MP(l, d), x = MP(l, u), y = MP(r, u), z = MP(r, d);
int vw = mp[w], vx = mp[x], vy = mp[y], vz = mp[z];
int v1 = 0, v2 = 0, v3 = 0, v4 = 0;
SII it1 = Sx[mpx[l]].upper_bound(d); if(it1 != Sx[mpx[l]].end() && *it1 < u) v1 = 1;
SII it2 = Sy[mpy[u]].upper_bound(l); if(it2 != Sy[mpy[u]].end() && *it2 < r) v2 = 1;
SII it3 = Sx[mpx[r]].upper_bound(d); if(it3 != Sx[mpx[r]].end() && *it3 < u) v3 = 1;
SII it4 = Sy[mpy[d]].upper_bound(l); if(it4 != Sy[mpy[d]].end() && *it4 < r) v4 = 1;
if(l == r && u == d) return -1;
if(l == r) return (v1 == 0 ? 1 : 0);
if(u == d) return (v2 == 0 ? 1 : 0);
int cnt = vw + vx + vy + vz;
int emp = (v1 == 0 && v2 == 0 && v3 == 0 && v4 == 0);
// choose 0
int res = (v1 == 1 && v2 == 1 && v3 == 1 && v4 == 1);
if(cnt == 0) return res;
// choose 1
if(vw == 1) res -= (v1 == 0 && v4 == 0 && v2 == 1 && v3 == 1);
if(vx == 1) res -= (v1 == 0 && v2 == 0 && v3 == 1 && v4 == 1);
if(vy == 1) res -= (v2 == 0 && v3 == 0 && v1 == 1 && v4 == 1);
if(vz == 1) res -= (v3 == 0 && v4 == 0 && v1 == 1 && v2 == 1);
if(cnt == 1) return res;
// choose 2
if(vw == 1 && vx == 1) res -= (v1 == 0 && v2 == 0 && v4 == 0 && v3 == 1);
if(vx == 1 && vy == 1) res -= (v1 == 0 && v2 == 0 && v3 == 0 && v4 == 1);
if(vy == 1 && vz == 1) res -= (v2 == 0 && v3 == 0 && v4 == 0 && v1 == 1);
if(vz == 1 && vw == 1) res -= (v1 == 0 && v3 == 0 && v4 == 0 && v2 == 1);
if(vw == 1 && vy == 1) res += emp;
if(vx == 1 && vz == 1) res += emp;
if(cnt == 2) return res;
// choose 3
if(vw == 1 && vx == 1 && vy == 1) res -= emp;
if(vx == 1 && vy == 1 && vz == 1) res -= emp;
if(vy == 1 && vz == 1 && vw == 1) res -= emp;
if(vz == 1 && vw == 1 && vx == 1) res -= emp;
if(cnt == 3) return res;
if(vw == 1 && vx == 1 && vy == 1 && vz == 1) res += emp;
return res;
}
能否在枚举矩形时直接把答案求出来呢?
我们先考虑没有横纵坐标相同的情况。记
:对应矩形 贡献。 :对应矩形 贡献。 :对应矩形 贡献。 :对应矩形 贡献。
对于有横纵坐标相同的情况,将所有点按横坐标为第一关键字从小到大排序,按纵坐标为第二关键字从小到大排序,执行以上算法,得到的答案仍然正确。
别看上面这句话轻描淡写——它对于解决本题实在是具有伟大的意义,它意味着可以将上面大量分类讨论归于一个简洁的算法,而不重不漏。
for(int i = 1; i <= K; ++i)
{
int U = INF, D = -INF;
Dec(ans, calc_val(p[i].fi, p[i].fi, p[i].se, p[i].se));
for(int j = i + 1; j <= K; ++j)
{
if(p[j].se >= U || p[j].se <= D) continue;
int mn = min(p[i].se, p[j].se);
int mx = max(p[i].se, p[j].se);
Inc(ans, calc_val(p[i].fi, p[j].fi, mx, mn));
Dec(ans, calc_val(p[i].fi, p[j].fi, mx, D));
Dec(ans, calc_val(p[i].fi, p[j].fi, U, mn));
Inc(ans, calc_val(p[i].fi, p[j].fi, U, D));
if(p[j].se >= p[i].se) U = p[j].se;
if(p[j].se <= p[i].se) D = p[j].se;
}
}
于是现在的问题是如何快速计算
对于一个
此处:
因此
const int inv6 = qwqmi(6);
const int inv4 = qwqmi(4);
const int inv30 = qwqmi(30);
int sum2(int x) { return mul(inv6, mul(x, mul(x + 1, 2 * x + 1))); }
int sum3(int x) { return mul(inv4, mul(sqr(x), sqr(x + 1))); }
int sum4(int x) { return mul(inv30, mul(x, mul(x + 1, mul(2 * x + 1, dec(mul(3, mul(x, x + 1)), 1))))); }
int cx[2], cy[2]; // w(len) = c[0] + c[1] * len
int func(int l, int r)
{
l = max(0, l - 1);
int c2 = mul(cx[0], cy[0]);
int c3 = inc(mul(cx[0], cy[1]), mul(cx[1], cy[0]));
int c4 = mul(cx[1], cy[1]);
int res = 0;
Inc(res, mul(c2, dec(sum2(r), sum2(l))));
Inc(res, mul(c3, dec(sum3(r), sum3(l))));
Inc(res, mul(c4, dec(sum4(r), sum4(l))));
return res;
};
int calc_val(int l, int r, int u, int d)
{
--l, ++r, --d, ++u;
if(l < 0 || d < 0 || r > n || u > m) return 0;
int mn = max(r - l, u - d), mx = min(n, m);
vector<int> vec = {mn, mx + 1, r + 1, u + 1, n - l + 1, m - d + 1};
sort(vec.begin(), vec.end());
auto coef = [&](int len, int l, int r, int lim, int *c)
{
if(len <= lim - l && len <= r) c[0] = l - r + 1, c[1] = 1;
else if(len <= lim - l && len > r) c[0] = l + 1, c[1] = 0;
else if(len > lim - l && len <= r) c[0] = lim - r + 1, c[1] = 0;
else c[0] = lim + 1, c[1] = MOD - 1;
};
int res = 0;
for(int i = 0; i + 1 < (int)vec.size(); ++i)
{
if(vec[i] < mn) continue;
if(vec[i] > mx) break;
if(vec[i] == vec[i + 1]) continue;
coef(vec[i], l, r, n, cx);
coef(vec[i], d, u, m, cy);
Inc(res, func(vec[i], vec[i + 1] - 1));
}
return res;
}
总时间复杂度
P8329 [ZJOI2022] 树
Problem
对于参数
第一棵树的生成方式是:节点
第二棵树的生成方式是:节点
要求对于任意
对所有
输出答案对
Solution
记
记
对二者分别做子集反演可以得到:
则:
其中
后面的部分是神仙 DP,笔者认为是更困难的一部分。
记
边界:
转移:(在第一棵树上给
-
: 。 -
: 。 -
: 。
这个过程就是:不断地将某些点纳入
对于参数
也许先对每个
彩蛋:QOJ# 4836. Tree。这题后来被搬到 ACM 里面去了:|
二项式反演
引子
这部分帮你快速了解二项式反演是什么以及它为什么是对的,但并不能解释更深入的东西。
我们仍然使用代入法进行证明。这里只考察第一个式子。
充分性:
当且仅当
必要性:读者自证。(太 naive,不想写了)
第一个式子给出了 钦定至多 与 恰好 的转换,第二个式子给出了 钦定至少 和 恰好 的转换。
从矩阵的角度推导二项式反演:反演公式的一般性
矩阵求逆。
从集合反演的角度推导二项式反演
同时作为 [AGC005D] ~K Perm Counting 一题 Bonus 的回答。
已知:
当
已知:
同理进行替换:
即:钦定至多型二项式反演是子集反演的特殊形式,钦定至多型二项式反演是超集反演的特殊形式。
由于集合反演的本质是容斥,因此我们最终还是会分析二项式反演与容斥的直接联系。
从容斥的角度推导二项式反演
这是最隐晦、最有意思的一部分,也是笔者仍未明白的一部分。
由广义容斥原理可以得到 钦定至少 型的二项式反演公式:
钦定至多 型的二项式反演可以由容斥的特殊情况推出:
设
由:
与:
可得:
令
如何在容斥意义上统一二项式反演、钦定至多型二项式反演是否有普适性应用等问题是笔者仍在思考的事情。
错排问题
Problem
求
Solution
设
枚举 恰好
反演:
钦定至多型二项式反演与容斥的关系
在本例中,我们令容斥全集为
定义此处
注意到:对于同一个
染色问题
Problem 1
Solution 1
设
枚举 恰好 有多少种颜色被使用以计算
反演:
Problem 2
Solution
此例讲述多元情况下二项式反演与容斥的关系。
设
枚举 恰好 有有多少行/列被染色以计算
令
对
对
得到
多元钦定至多型二项式反演与容斥的关系
在本例中,定义一个染色状态
令
定义此处每个容斥素
注意到:对于同一个二元组
Problem 3
Solution 3
设
枚举 恰好 用
反演:
BZOJ2839 集合计数
Problem
一个有
Solution
此例展示钦定至少型二项式反演在计数中的应用。
设
枚举 恰好 有
反演:
钦定至少型二项式反演与容斥的关系
钦定至少型二项式反演是广义容斥原理结合第一反演公式的普遍性结果。
鉴于该形式的二项式反演在容斥意义下存在不依赖于任何性质的推导方法,它的应用会更加广泛(从表面上看确实是这样)。
本例中拥有 “
如果没有上述特殊性质,可以考虑用 DP 计算
P5505 [JSOI2011] 分特产
Problem
把
Solution
设
其实是扩展容斥原理作为经典容斥原理的特殊形式,这我们之前已经提到过了。
代入即可。
P4859 已经没有什么好害怕的了
Problem
给出两个长度均为
现要将
Solution
如果
设
将
其中
P6478 [NOI Online #2 提高组] 游戏
Problem
给定一棵
把黑白点两两配对,对于
Solution
设
设
其中
CF285E Positions in Permutations
Problem
称一个
Solution
这完全就是 [AGC005D] ~K Perm Counting 嘛!
P5339 [TJOI2019] 唱、跳、rap和篮球
Problem
我认为我没有必要简化题面。
大中锋的学院要组织学生参观博物馆,要求学生们在博物馆中排成一队进行参观。他的同学可以分为四类:一部分最喜欢唱、一部分最喜欢跳、一部分最喜欢rap,还有一部分最喜欢篮球。如果队列中
Solution
记
答案为:
其实也是扩展容斥原理作为经典容斥原理的特殊形式,这我们之前已经提到过了。
现在来求
记
对每个
P4491 [HAOI2018] 染色
Problem
有一个长度为
如果恰好出现了
求所有可能的染色方案获得的愉悦度之和对
Solution
此例展现 NTT 优化二项式反演。
设
由
令
令
即:翻转
可以线性求出
P5401 [CTS2019] 珍珠
Problem
有
求至少能选出
请输出概率乘上
Solution
记
也就是说,出现次数为奇数的数的个数不超过
当
设
经常用 NTT 优化二项式反演的朋友们知道,只需求出所有的
杀杀杀!
卷卷卷。
P5400 [CTS2019] 随机立方体
Problem
有一个
Solution
神仙题。
设
经常玩 Minecraft 的人知道,我们是可以使用 Minecraft 直观体会如何计算
记
钦定
被极大数影响到的位置有
选出被影响到的位置的数值:
未被影响到的位置可以随便排列:
被影响到的位置可以参考 cmd 的 MC 建模:羊毛代表极大数,方块代表被极大数影响到的位置。不算空气块:|
钦定黄羊毛 < 蓝羊毛 < 红羊毛 < 绿羊毛。一个被影响的位置的颜色是影响到它的最小极大数所代表的颜色,表示我们在这个颜色时将该位置填上数。
然后由内向外填数。对于自外向内的第
于是将选出的权值填进这
最后算概率要除以
整理一下:
使用线性逆元可以做到严格线性:|。但是带老哥也能过。
本文作者:Schucking_Sattin
本文链接:https://www.cnblogs.com/Schucking-Sattin/p/18007448
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?