Prufer序列 学习笔记

文章目录

P r u f e r Prufer Prufer 序列

P r u f e r Prufer Prufer 序列可以将一棵 n n n 个点的有编号无根树 转化成一个长度为 n − 2 n - 2 n2,值域在 [ 1 , n ] [1, n] [1,n] 的序列。也可以将 任意一个 长度为 n − 2 n - 2 n2,值域在 [ 1 , n ] [1, n] [1,n] 的序列转化成一棵 有编号无根树。可以理解成有标号完全图的生成树与数列之间的双射,常用于对树计数的问题。

对树建立 P r u f e r Prufer Prufer 序列

建立过程:
每次找到编号最小的叶子,往序列末尾加入它所连接的节点编号,然后删掉这个叶子。重复 n − 2 n - 2 n2 次后只剩下两个节点结束。

实现方式:
考虑维护指针 p p p 指向当前最小的叶子编号,每次删掉 p p p 后判断 p p p 相连的点是否变成了叶子并且编号小于 p p p,如果满足这两个条件那么接着删掉这个点。重复这个过程直到当前叶子相连的点不满足上述条件,然后令 p p p 不断自增直到找到下一个叶子。

正确性说明:

  • 每次删掉一个叶子后最多只会增加一个叶子,并且如果增加了叶子那么一定是当前叶子所连的点。
  • 设当前叶子为 p p p,删掉 p p p 后新增叶子 q q q
  • q < p q < p q<p,那么 q q q 一定比其它叶子更小,删 q q q 是正确的。
  • q > p q > p q>p,那么后面 p p p 自增时一定能枚举到,因此不用管。

这样指针只会移动 O ( n ) O(n) O(n) 次,每个点只会被删除一次,复杂度 O ( n ) O(n) O(n)

代码:

inline void TP() { // 树 -> prufer序列for(int i = 1; i < n; i ++ ) deg[fa[i]] ++;int p = 1;for(int i = 1; i <= n - 2; ) {int j = i;while(deg[p]) p ++; pf[j ++] = fa[p]; deg[fa[p]] --;int tp = p;while(j <= n - 2 && !deg[fa[p]] && fa[p] < tp) p = fa[p], pf[j ++] = fa[p], deg[fa[p]] --;i = j; p = ++ tp;}
}

P r u f e r Prufer Prufer 序列的性质:

  • 构造完 P r u f e r Prufer Prufer 序列后原树会剩下两个节点,其中一定有一个为 n n n
  • 原树中的每个点一定在 P r u f e r Prufer Prufer 序列中出现 d e g − 1 deg - 1 deg1 次,没有出现过的就是叶子节点。

从上述建立过程可以看出来:
任意一棵 n n n 个点有编号无根树都可以建立出唯一的 P r u f e r Prufer Prufer 序列,并且本质不同的树对应的 P r u f e r Prufer Prufer 序列一定不同
这就完成了 从树到 P r u f e r Prufer Prufer 序列 的单射。

P r u f e r Prufer Prufer 序列重建树

建立过程:
对于给定的长为 n − 2 n - 2 n2,值域在 [ 1 , n ] [1, n] [1,n] p r u f e r prufer prufer 序列,我们可以统计每个点的出现次数来求出每个点的度数。考虑每次找到编号最小的叶子来确定与它相连的点,显然这个相连点应该是当前 P r u f e r Prufer Prufer 序列的第一个数。然后把这个叶子删掉,令相连点的度数减一,然后把 P r u f e r Prufer Prufer 序列的第一个数删掉,重复这个过程 n − 2 n - 2 n2 次。剩下两个叶子,把它们之间连一条边即可。

实现方式:
注意到最后剩下的两个叶子也一定有一个是 n n n,我们将 P r u f e r Prufer Prufer 序列的末尾补上一个 n n n,然后重复上述过程 n − 1 n - 1 n1 次就可以连出 n − 1 n - 1 n1 条边。

与建立 P r u f e r Prufer Prufer 序列的过程类似,考虑维护指针 p p p 表示当前编号最小的叶子,然后每次删掉叶子后判断新增叶子 q q q 是否比 p p p 小,如果是的话就接着去连 q q q 的出边,否则就不断自增 p p p 直到找到下一个叶子。可以看作对于当前叶子 p p p P r u f e r Prufer Prufer 序列的开头就是以 n n n 为根下 p p p 的父亲节点

也不难看出 → \to 序列序列 → \to 的过程是互逆的。一个 P r u f e r Prufer Prufer 序列重建的树对应的 P r u f e r Prufer Prufer 序列也一定是这个 P r u f e r Prufer Prufer 序列。

复杂度 O ( n ) O(n) O(n)

代码:

inline void PT() { // prufer序列 -> 树pf[n - 1] = n;for(int i = 1; i <= n - 2; i ++ ) deg[pf[i]] ++;int p = 1;for(int i = 1; i <= n - 1;) {int j = i;while(deg[p]) p ++; fa[p] = pf[j ++], deg[fa[p]] --;int tp = p;while(j <= n - 1 && !deg[fa[p]] && fa[p] < tp) p = fa[p], fa[p] = pf[j ++], deg[fa[p]] --;i = j; p = ++ tp;}
}

由上述重构过程可以看出:
任意一个长度为 n − 2 n - 2 n2,值域在 [ 1 , n ] [1, n] [1,n] 的序列,都能作为一个 P r u f e r Prufer Prufer 序列唯一的构造出一棵树。并且任意两个不同 P r u f e r Prufer Prufer 序列构造的树都是不同的

这样就完成了从 P r u f e r Prufer Prufer 序列到树 的单射。结合上边,就得到了:

n n n 个点编号为 1 ∼ n 1 \sim n 1n 的无根树与长度为 n − 2 n - 2 n2,值域为 [ 1 , n ] [1, n] [1,n] 的序列双射

应用

Cayley 公式

n n n 个点有编号的完全图生成树个数为 n n − 2 n^{n - 2} nn2

证明:双射即可。

[HNOI2004] 树的计数

题意:
给定 n n n 个点的度数 d 1 , … d n d_1,\dots d_n d1,dn,任意两个点之间可以连边,问有多少个满足度数数组的生成树。

1 ≤ n ≤ 150 1 \leq n \leq 150 1n150

分析:
特判 n = 1 n = 1 n=1 的边界情况。那么任意一个点的度数不能为 0 0 0,并且所有点的度数和应为 2 n − 2 2n - 2 2n2
一个点只要在 P r u f e r Prufer Prufer 序列中出现 d i − 1 d_i - 1 di1 即满足构造出来的树中度数为 d i d_i di。这就是多重集的全排列。

CODE:

#include<bits/stdc++.h>
using namespace std;
const int N = 155;
typedef long long LL;
int n, deg[N], all;
LL res = 1, C[N][N];
int main() {scanf("%d", &n); int all = n - 2;for(int i = 0; i <= n; i ++ ) for(int j = 0; j <= i; j ++ ) if(!j) C[i][j] = 1;else C[i][j] = C[i - 1][j - 1] + C[i - 1][j];for(int i = 1; i <= n; i ++ ) {scanf("%d", &deg[i]);if(deg[i] == 0) {if(n == 1) {puts("1"); return 0;}else {puts("0"); return 0;}}res = res * C[all][deg[i] - 1];all -= deg[i] - 1;}if(all != 0) puts("0");else cout << res << endl;return 0;
}

「雅礼集训 2017 Day8」共

题意:
给定 n , k n, k n,k。 你需要求出有多少个编号为 1 ∼ n 1 \sim n 1n,以 1 1 1 为根的无向树,满足深度为奇数的点恰好有 k k k 个。 1 1 1 的深度认为是 1 1 1

1 ≤ k < n ≤ 5 × 10 5 1 \leq k < n \leq 5 \times 10^5 1k<n5×105

分析:
显然可以将点按照深度的奇偶性分成两类,这将树变成了一张二分图。
1 1 1 划分到左部点中,那么需要从剩下的 n − 1 n - 1 n1 个编号里选出 k − 1 k - 1 k1 个分到左部点。答案就是 ( n − 1 k − 1 ) × S ( k , n − k ) \binom{n - 1}{k - 1} \times S(k, n - k) (k1n1)×S(k,nk)
其中 S ( a , b ) S(a, b) S(a,b) 表示一张左部点有 a a a 个,右部点有 b b b 个的有标号完全二分图的生成树个数。
答案是 a b − 1 b a − 1 a^{b-1}b^{a - 1} ab1ba1
证明:
对于这样二分图的生成树, P r u f e r Prufer Prufer 序列构造过程的末尾一定剩下一个左部点和一个右部点。因此它的 P r u f e r Prufer Prufer 序列一定有 b − 1 b - 1 b1 个左部点和 a − 1 a - 1 a1 个右部点。
对于这两部分的构成的子序列内部,如果确定了编号和顺序。那么两部分之间在 P r u f e r Prufer Prufer 序列上的顺序就定下来了。因此总方案数就是 a b − 1 b a − 1 a^{b - 1}b^{a - 1} ab1ba1

CODE:

// 这种双射还真是秒啊
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
typedef long long LL;
int n, k, p;
inline LL Pow(LL x, LL y) {LL res = 1, k = x;while(y) {if(y & 1) res = res * k % p;y >>= 1;k = k * k % p;}return res;
}
LL fac[N], inv[N];
int main() {cin >> n >> k >> p;fac[0] = 1; for(int i = 1; i < N; i ++ ) fac[i] = fac[i - 1] * i % p;inv[N - 1] = Pow(fac[N - 1], p - 2); for(int i = N - 2; i >= 0; i -- ) inv[i] = inv[i + 1] * (i + 1) % p;int L = k, R = n - k; LL res = fac[n - 1] * inv[k - 1] % p * inv[n - k] % p * Pow(L, R - 1) % p * Pow(R, L - 1) % p;cout << res << endl;return 0;
}

[THUPC 2018] 城市地铁规划

题意:

给定一个 n , k , m o d n, k, mod n,k,mod,然后给你一个 k k k 次多项式 f ( x ) f(x) f(x) 的每一项系数 a 0 , … , a k a_0,\dots,a_k a0,,ak。对于一个度数为 d d d 的点,它的贡献为 f ( d ) ( m o d m o d ) f(d) \pmod{mod} f(d)(modmod)。你可以给编号为 1 ∼ n 1 \sim n 1n 的点之间任意连边,求所有生成树中所有点贡献和最大的方案,输出最大贡献和以及一组构造。

1 ≤ n ≤ 3000 , 0 ≤ k ≤ 10 , m o d = 59393 1 \leq n \leq 3000, 0 \leq k \leq 10, mod = 59393 1n3000,0k10,mod=59393

分析:
首先预处理出 i ∈ [ 1 , n ] i\in [1, n] i[1,n] 的所有 w i = f ( i ) w_i = f(i) wi=f(i)
注意到任意一个 P r u f e r Prufer Prufer 序列都能构造出一棵树,并且在这棵树上一个点的度数为它在序列中的出现次数加一。因此有一个暴力的 d p dp dp
f i , j f_{i, j} fi,j 表示考虑了编号为 1 ∼ i 1 \sim i 1i 的点, 这些点在 P r u f e r Prufer Prufer 序列的出现总次数为 j j j 的最大代价。转移枚举 i + 1 i + 1 i+1 的出现次数 k k k 即可。最后的答案就是 f n , n − 2 f_{n, n - 2} fn,n2
但是这样 d p dp dp 的复杂度为 O ( n 3 ) O(n^3) O(n3),考虑优化:
注意到我们不关心每个点的出现次数,只关心 每种出现次数有几个点。 所以可以以出现次数为阶段 d p dp dp
f i , j f_{i, j} fi,j 表示考虑了 1 ∼ i 1 \sim i 1i 这些出现次数,当前总出现次数为 j j j 的最大代价。
那么转移是: f i , j = max ⁡ k = 0 ⌊ j i ⌋ ( f i − 1 , j − i × k + k × w i + 1 ) \Large{f_{i, j} = \max\limits_{k = 0}^{\left \lfloor \frac{j}{i} \right \rfloor}}(f_{i - 1, j - i \times k}+k \times w_{i + 1}) fi,j=k=0maxij(fi1,ji×k+k×wi+1)

现在转移复杂度就变成 O ( n ln ⁡ n ) O(n\ln n) O(nlnn),总复杂度 O ( n 2 ln ⁡ n ) O(n^2\ln n) O(n2lnn)
但是好像有个问题,我们没有计算度数为 1 1 1 的点的贡献,并且记录的出现次数也没办法体现有多少个点的度数不是 1 1 1
肯定不能多加一维来记录。我们考虑初始令 f 0 , 0 = n × w 1 f_{0, 0} = n \times w_1 f0,0=n×w1,然后每次转移除了 + k × w i +k\times w_{i} +k×wi 还要 − k × w 1 -k\times w_1 k×w1 表示把这 k k k 个点的代价换掉。
这样就对了。构造只需要对每个状态记录前驱,然后任意拿一些编号构造 p r u f e r prufer prufer 序列即可。

复杂度 O ( n 2 ln ⁡ n ) O(n^2 \ln n) O(n2lnn)
CODE:

// prufer 序列与有标号无根树双射的好处:任意 prufer 序列都能构造出一棵树。因此只需要考虑 prufer 序列最优即可
// 对每个点去 dp 它在 prufer 序列出现多少次,复杂度 n^3 优化不了。
// 但是我们只关心每种次数有多少个。 对每个次数 dp 复杂度就降到了 n^2 ln n
#include<bits/stdc++.h>
using namespace std;
const int N = 4010;
const int mod = 59393;
int n, k, a[N];
int val[N], f[N][N], pre[N][N]; // f[i][j] 表示考虑了前 1~i 这些次数, 当前用的总次数为 j 的最优值
int fa[N], prufer[N], tot, p, deg[N];
inline void get_prufer(int x, int y) {if(!x) return ;if(pre[x][y] < y) {for(int i = 1; i <= (y - pre[x][y]) / x; i ++ ) {for(int j = 1; j <= x; j ++ ) prufer[++ tot] = p;p ++;}}get_prufer(x - 1, pre[x][y]);
}
inline void PT() {prufer[n - 1] = n;for(int i = 1; i <= n - 1; i ++ ) deg[prufer[i]] ++;int p = 1;for(int i = 1; i <= n - 1;) {int j = i;while(deg[p]) p ++; fa[p] = prufer[j ++], deg[fa[p]] --;int tp = p;while(j <= n - 1 && !deg[fa[tp]] && fa[tp] < p) tp = fa[tp], fa[tp] = prufer[j ++], deg[fa[tp]] --;i = j; p ++;}
}
int main() {scanf("%d%d", &n, &k);for(int i = 0; i <= k; i ++ ) scanf("%d", &a[i]);for(int i = 0; i <= n; i ++ ) {int v = 1;for(int j = 0; j <= k; j ++ ) {val[i] = (val[i] + v * a[j] % mod) % mod;v = v * i % mod;}}if(n == 1) {printf("0 %d\n", val[0]); return 0;}memset(f, 0xcf, sizeof f); f[0][0] = n * val[1]; // 初始所有度数都是 1for(int i = 1; i <= n - 2; i ++ ) {for(int j = 0; j <= n - 2; j ++ ) {for(int k = 0; k * i <= j; k ++ ) {if(f[i - 1][j - k * i] + k * val[i + 1] - k * val[1] > f[i][j]) {f[i][j] = f[i - 1][j - k * i] + k * val[i + 1] - k * val[1];pre[i][j] = j - k * i;}}}}printf("%d %d\n", n - 1, f[n - 2][n - 2]);p = 1;get_prufer(n - 2, n - 2);PT();for(int i = 1; i < n; i ++ ) printf("%d %d\n", i, fa[i]);return 0;
}

CF156D Clues

题意:
给定一张 n n n 个点, m m m 条边的有标号无向图,它有 k k k 个连通块,求添加 k − 1 k - 1 k1 条边使得图联通的方案数。答案对 p p p 取模。

1 ≤ n , m ≤ 10 5 , 1 ≤ p ≤ 10 9 1 \leq n,m \leq 10^5, 1 \leq p \leq 10^9 1n,m105,1p109

分析:
将连通块缩成一个点,就转换成了类似完全图求生成树的问题。
如果用连通块的编号来构造 P r u f e r Prufer Prufer 序列,那么答案就是 k k − 2 k^{k - 2} kk2。这显然不对,原因在于一个连通块编号实际上代表了 s i z e size size 个点。
如果对于每一种以连通块编号构造的 P r u f e r Prufer Prufer 序列,我们都把每个连通块的编号换成任意连通块内的点的编号。那么这实际上就等于将所有点的编号拿出来构造长为 k − 2 k - 2 k2 P r u f e r Prufer Prufer 序列,方案数为 n k − 2 n^{k - 2} nk2
这对不对呢?很遗憾,它也是不对的。
我们来尝试理解这样得到的 P r u f e r Prufer Prufer 序列有什么实际含义:相当于每次取出度数为 0 0 0 的编号最小的连通块,然后把这个连通块和 P r u f e r Prufer Prufer 序列开头编号的连通块相连,并且根据 P r u f e r Prufer Prufer 序列我们知道连向的点的编号就是序列开头数字。
然后你就能发现问题所在了:我们不知道当前的 “叶子” 连出去的点编号是什么!!
因此开始的时候将答案乘上 ∏ s i z e i \prod size_i sizei 表示先对每个连通块钦定一个往外连出去的点的编号,然后再乘上 n k − 2 n^{k - 2} nk2 就行。

最后答案就是 n k − 2 ∏ s i z e i n^{k - 2}\prod size_i nk2sizei。复杂度线性。

CODE:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int n, m, mod, sz[N], bin[N];
int Find(int x) {return x == bin[x] ? x : bin[x] = Find(bin[x]);}
inline void Merge(int u, int v) {int f1 = Find(u), f2 = Find(v);if(f1 != f2) sz[f2] += sz[f1], bin[f1] = f2;
}
inline LL Pow(LL x, LL y) {LL res = 1, k = x;while(y) {if(y & 1) res = res * k % mod;y >>= 1;k = k * k % mod;}return res;
}
int main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m >> mod;for(int i = 1; i <= n; i ++ ) bin[i] = i, sz[i] = 1;for(int i = 1; i <= m; i ++ ) {int u, v; cin >> u >> v;Merge(u, v);}LL res = 1; int cnt = 0;for(int i = 1; i <= n; i ++ ) {if(Find(i) == i) res = res * sz[i] % mod, cnt ++;}if(cnt == 1) {cout << (1 % mod) << endl; return 0;}else {		res = res * Pow(n, cnt - 2) % mod;cout << res << endl;}return 0;
}

[ARC106F] Figures

题意:
N N N 个点,每个点有 d i d_i di互不相同、可被区分 的孔,每次可以选择两个不同点,连接两个未被连接过的孔,有多少种方案使得最后形成一棵树。合法方案中可以不把孔填满。答案对 998244353 998244353 998244353

2 ≤ N ≤ 2 × 10 5 , 1 ≤ d i < 998244353 2 \leq N \leq 2 \times 10^5, 1\leq d_i < 998244353 2N2×105,1di<998244353

分析:
和上道题非常类似,只是一个联通块中的一个点只能被连接一次,上一道题是可以连接任意次。
一样的思考方式,如果我们把所有孔的编号拿出来,有 M = ∑ d i M = \sum d_i M=di 个孔,用 A M N − 2 A_{M}^{N - 2} AMN2 来生成 P r u f e r Prufer Prufer 序列。
这样还是不正确的,错误原因仍然是每个点作为叶子连出去时没确定一个孔。
如果最后考虑这个孔是谁,我们还需要知道每个点有多少个孔在 P r u f e r Prufer Prufer 序列出现,这不太好。
还是最开始就考虑这个孔是谁,先乘上 ∏ d i \prod d_i di 的系数,然后这些孔就不能用了,因此我们用 A M − N N − 2 A_{M - N}^{N - 2} AMNN2 来构建 P r u f e r Prufer Prufer 序列。这样就对了,答案就是 A M − N N − 2 ∏ d i A_{M - N}^{N - 2}\prod d_i AMNN2di

复杂度线性。

CODE:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long LL;
const LL mod = 998244353;
int n, d[N];
LL res = 1;
inline LL A(LL n, LL m) {if(n < m) return 0;LL res = 1;for(LL i = n; i > n - m; i -- ) res = res * (i % mod) % mod;return res;
}
int main() {scanf("%d", &n); LL s = 0;for(int i = 1; i <= n; i ++ ) {scanf("%d", &d[i]); s += d[i] - 1;res = res * d[i] % mod;}res = res * A(s, n - 2) % mod; cout << res << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/85239.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/85239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高性能场景使用Protocol Buffers/Apache Avro进行序列化怎么实现呢

我们以Protocol Buffers&#xff08;Protobuf&#xff09;和Apache Avro为例&#xff0c;分别展示高性能序列化的实现方式。 由于两者都需要定义Schema&#xff0c;然后生成代码&#xff0c;因此步骤包括&#xff1a; 1. 定义Schema文件 2. 使用工具生成Java类 3. 在代码中…

iOS端网页调试 debug proxy策略:项目中的工具协同实践

移动开发中的调试&#xff0c;一直是效率瓶颈之一。特别是当前 Web 前端与 App 原生高度耦合的背景下&#xff0c;页面调试不仅受限于浏览器&#xff0c;还要面对 WebView 实现差异、系统权限控制、设备多样性等复杂情况。 但我们是否可以构建一套**“设备无关”的调试工作流*…

springboot项目启动报错:spring boot application in default package

启动类报错&#xff1a; 问题&#xff1a; springboot的启动方法不能直接在java目录下 解决&#xff1a; 1.使用CompentScan 和EnableAutoConfiguration注解 2.启动类放在java目录下的package目录下

机器学习实验报告5-K-means 算法

4.1 k-means算法简介 聚类分析&#xff0c;作为机器学习领域中的一种无监督学习方法&#xff0c;在数据探索与知识发现过程中扮演着举足轻重的角色。它能够在没有先验知识或标签信息的情况下&#xff0c;通过挖掘数据中的内在结构和规律&#xff0c;将数据对象自动划分为多个类…

【已解决】yoloOnnx git工程部署

首先 yoloonnx一个VS工程下来整个工程大概1-2个g的大小因此在git的过程中总是会因为文件超过100M而触发报错&#xff0c;上传不上去&#xff0c;因此现在需要做一个过滤才能把工程重新上传上去&#xff0c;那么这个时候别人需要下载下来的时候确实不完整的工程&#xff0c;因此…

如何轻松地将照片从电脑传输到安卓手机

一些安卓用户正在寻找有效可靠的方法&#xff0c;将照片从电脑传输到安卓设备。如果您也想将有趣或难忘的照片导入安卓手机或平板电脑&#xff0c;可以参考这篇文章&#xff0c;它提供了 6 种可靠的方法&#xff0c;让您轻松传输照片。 第 1 部分&#xff1a;如何通过 Android …

准备纯血鸿蒙理论高级认证的一些心得

最近在准备纯血鸿蒙理论高级认证&#xff0c;一些心得记录下来&#xff0c;希望早日考过高级&#xff01; 一、考试目标&#xff1a; HarmonyOS核心技术理念HarmonyOS应用架构设计ArkTS原理和实践ArkUI开发HarmonyOS关键技术能力开发工程管理、代码编辑、调试与定位应用上架运…

义乌购拍立淘API接入指南

一、接口概述 拍立淘是义乌购平台提供的以图搜货服务&#xff0c;通过HTTP RESTful API实现。当前版本为v3.2&#xff0c;支持JPG/PNG格式图片&#xff08;≤5MB&#xff09;&#xff0c;返回相似商品列表及供应链信息。 二、接入准备 申请开发者账号 # 开发者注册示例&…

Web 连接和跟踪

大家读完觉得有帮助记得及时关注和点赞&#xff01;&#xff01;&#xff01; 抽象 网络跟踪是一种普遍且不透明的做法&#xff0c;可实现个性化广告、重新定位和转化跟踪。 随着时间的推移&#xff0c;它已经演变成一个复杂的侵入性生态系统&#xff0c;采用越来越复杂的技术来…

前端技术栈与 SpreadJS 深度融合:打造高效数据表格应用

引言 在当今数字化的时代&#xff0c;数据表格应用在各种 Web 项目中扮演着至关重要的角色。从企业级的管理系统到电商平台的商品展示&#xff0c;数据表格都是用户与数据交互的重要界面。前端技术栈如 JavaScript、HTML 和 CSS 为构建用户界面提供了强大的工具和方法&#xf…

如何用ai描述缺陷(bug)

附件1&#xff1a; 附件2&#xff1a; 将附件1和附件2发送给deepseek&#xff0c;且输入对话框的文字&#xff1a; 然后进入禅道用户登录 - 禅道 ### **缺陷报告&#xff1a;登录功能无响应缺陷** **提交平台**&#xff1a;禅道缺陷管理系统 **发现环境**&#xff1a;测试环…

软考 系统架构设计师系列知识点之杂项集萃(89)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;88&#xff09; 第161题 下面可提供安全电子邮件服务的是&#xff08; &#xff09;。 A. RSA B. SSL C. SET D. S/MIME 正确答案&#xff1a;D。 解析&#xff1a; MIME&#xff08;Multi…

开源 Arkts 鸿蒙应用 开发(一)工程文件分析

文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发&#xff0c;公司安排开发app&#xff0c;临时学习&#xff0c;完成app的开发。开发流程和要点有些记忆模糊&#xff0c;赶紧记录&#xff0c;防止忘记。 相关链接&#xff1a; 开源 Arkts …

protobuf遇到protoc-gen-go: unable to determine Go import path for “xxx“

问题 这个错误是因为 .proto 文件中缺少必需的 go_package 选项。在 protobuf 生成 Go 代码时&#xff0c;这是关键配置项。 pandaVM:~/dev/pb$ protoc --go_out. pb.proto protoc-gen-go: unable to determine Go import path for "pb.proto"Please specify eithe…

linux unix socket 通信demo

好&#xff0c;下面是已经整合完善的版本&#xff1a; ✅ 功能点&#xff08;你要求的全部实现了&#xff09;&#xff1a; Unix Domain Socket (SOCK_STREAM) 服务端先启动&#xff1a;正常通信 客户端先启动&#xff1a;等待服务端直到连接成功 客户端每秒发送一条消息 服务端…

近期GitHub热榜推荐

【1】fluentui-system-icons (HTML) &#x1f468;‍&#x1f4bb; 作者&#xff1a; microsoft &#x1f4e6; 仓库&#xff1a; microsoft / fluentui-system-icons &#x1f310; 链接&#xff1a; https://github.com/microsoft/fluentui-system-icons ⭐ 星标&#xf…

Jupyter 是什么?基于浏览器的交互式计算环境

&#x1f9e0; 一、Jupyter 是什么&#xff1f; Jupyter 是一个基于浏览器的交互式计算环境&#xff0c;名字取自Julia Python R 三种语言&#xff0c;但现在已支持超过40种编程语言。它最核心的功能是让你在同一个文档&#xff08;.ipynb 文件&#xff09;中混合编写代码、…

CTF解题:[NSSCTF 2022 Spring Recruit]弱类型比较绕过

一、漏洞背景介绍 在 CTF&#xff08;Capture The Flag&#xff09;竞赛和 Web 安全测试中&#xff0c;PHP 语言的类型比较漏洞是常见的考点。这类漏洞源于 PHP 的弱类型特性&#xff0c;即当使用进行比较时&#xff0c;PHP 会自动进行类型转换&#xff0c;从而导致一些不符合…

【SQL】存储过程 vs 普通 SQL

一、存储过程 vs 普通 SQL 的核心区别 先明确两者的本质&#xff1a; 普通 SQL&#xff1a;是直接执行的查询 / 操作语句&#xff08;如SELECT、INSERT&#xff09;&#xff0c;每次执行都要编译&#xff0c;逻辑写在应用端或直接运行。存储过程&#xff1a;是预编译并存储在…

Vue.js第一节

初识Vue、插值操作、属性绑定 初识&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>D…