【6】组合计数学习笔记
前言
关于今天发现自己连快速幂都忘记怎么写这件事
这篇博客是组合计数基础,由于大部分内容都是 6 6 6 级,所以我就给整个提高级的组合数学评了 6 6 6 级。
组合计数基础
加法原理与乘法原理
加法原理(分类计数原理):完成一件事有 n n n 类方法,第一类办法有 m i m_i mi 种,第二类办法有 m 2 m_2 m2 种……第 n n n 类办法有 m n m_n mn 种,那么完成这件事的方法数(记为 N N N)为:
N = m 1 + m 2 + ⋯ + m n N=m_1+m_2+\dots+m_n N=m1+m2+⋯+mn
乘法原理(分步计数原理):完成一件事有 n n n 步,第一类步有 m i m_i mi 种方法,第二步有 m 2 m_2 m2 种方法……第 n n n 步有 m n m_n mn 种方法,那么完成这件事的方法数(记为 N N N)为:
N = m 1 m 2 … m n N=m_1m_2\dots m_n N=m1m2…mn
加法原理步骤相互独立,任何一种都能独立完成这件事;乘法原理步骤缺一不可,缺少任意一种就不能完成这件事。
排列与组合
排列:从 n n n 个不同元素中取出 m m m 个元素,按照不同顺序排成一列,叫做从 n n n 个不同元素中取出 m m m 个元素的排列,记作 A n m A^{m}_n Anm 。
排列数计算公式:
A n m = n ( n − 1 ) ( n − 2 ) … ( n − m + 1 ) = n ! ( n − m ) ! A^{m}_n=n(n-1)(n-2)\dots(n-m+1)=\frac{n!}{(n-m)!} Anm=n(n−1)(n−2)…(n−m+1)=(n−m)!n!
组合:从 n n n 个不同元素中取出 m m m 个元素,并成一组,叫做从 n n n 个不同元素中取出 m m m 个元素的组合,记作 C n m C^{m}_n Cnm 。
组合数计算公式:
C n m = A n m A m m = n ( n − 1 ) ( n − 2 ) … ( n − m + 1 ) m ! = n ! m ! ( n − m ) ! C^{m}_n=\frac{A^{m}_n}{A^m_m}=\frac{n(n-1)(n-2)\dots(n-m+1)}{m!}=\frac{n!}{m!(n-m)!} Cnm=AmmAnm=m!n(n−1)(n−2)…(n−m+1)=m!(n−m)!n!
与顺序有关的为排列问题,与顺序无关的为组合问题。
例题 1 1 1 :
由 0 , 1 , 2 , 3 , 4 , 5 0,1,2,3,4,5 0,1,2,3,4,5 可以组成多少个没有重复数字的五位奇数?
由于首位和末位有特殊要求,应该优先安排,以免不合要求的元素占了这两个位置。
先排末位有 C 3 1 C^1_3 C31 种方法,再排首位有 C 4 1 C^1_4 C41 种方法,最后排剩下的有 A 4 3 A^3_4 A43 种方法。
最后由乘法原理得到答案 N N N 为:
N = C 3 1 C 4 1 A 4 3 = 288 N=C^1_3C^1_4A^3_4=288 N=C31C41A43=288
例题 2 2 2 :
7 7 7 种不同的花种在排成一列的花盆里,若两种葵花不种在中间也不种在两边,有多少不同的种法?
由于特殊的两种葵花有特殊要求,应该优先安排,以免不合要求的元素占了这四个位置。
先排两盆特殊的葵花有 A 4 2 A^2_4 A42 种方法,再排剩下的有 A 5 5 A^5_5 A55 种方法。
最后由乘法原理得到答案 N N N 为:
N = A 4 2 A 5 5 = 1440 N=A^2_4A^5_5=1440 N=A42A55=1440
组合数的性质:
1 1 1 : C 0 0 = C n n = 1 C^0_0=C^n_n=1 C00=Cnn=1
2 2 2 : C n m = C n n − m C^m_n=C^{n-m}_n Cnm=Cnn−m
原因:从 n n n 个不同元素中取出 m m m 个元素,也就是从 n n n 个不同元素中不选择 n − m n-m n−m 个元素,方法数一样。
3 3 3 : C m n = C m − 1 n − 1 + C m − 1 n C^n_m=C^{n-1}_{m-1}+C^{n}_{m-1} Cmn=Cm−1n−1+Cm−1n
原因:从 n n n 个不同元素中取出 m m m 个元素,如果其中一个元素不取,那么就变成了从 n − 1 n-1 n−1 个不同元素中取出 m m m 个元素;如果其中一个元素取,那么就变成了从 n − 1 n-1 n−1 个不同元素中取出 m − 1 m-1 m−1 个元素。再根据加法原理,得出这条性质。
组合数的求法
求法 1 1 1 :杨辉三角递推(预处理)
适用范围: n , m n,m n,m 较小。
根据组合数的第 3 3 3 条性质,可以递推求出某一范围内的所有组合数。由于最后推完会发现其实是杨辉三角,所以也叫杨辉三角递推。
c[0][0]=1;
for(int i=1;i<=k;i++)c[i][0]=c[i][i]=1;
for(int i=1;i<=k;i++)for(int j=1;j<i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1];
时间复杂度: O ( n m ) O(nm) O(nm)
求法 2 2 2 :逆元(组合数取余)
适用范围:能保证逆元存在时。
由逆元的定义,我们可以推出这个式子:
C n m = n ! m ! ( n − m ) ! = n ! × i n v ( m ! ) × i n v [ ( n − m ) ! ] C^{m}_n=\frac{n!}{m!(n-m)!}=n!\times inv(m!)\times inv[(n-m)!] Cnm=m!(n−m)!n!=n!×inv(m!)×inv[(n−m)!]
long long power(long long a,long long p,long long m)
{long long x=a,ans=1;while(p){if(p%2==1)ans=(x%m*ans%m)%m;p/=2;x=(x%m*x%m)%m;}return ans;
}long long get_c(long long n,long long k,long long m)
{k=min(k,n-k);long long r1=1,r2=1;for(int i=n-k+1;i<=n;i++)r1=(r1%m*i%m)%m;for(int i=1;i<=k;i++)r2=(r2%m*i%m)%m;return (r1%m*power(r2,m-2,m)%m)%m;
}
对于逆元,直接费马小定理或扩展欧几里得求就行了。【7】逆元学习笔记
时间复杂度: O ( n + m ) O(n+m) O(n+m)
二项式定理
二项式定理基本形式:
( a + b ) n = ∑ k = 0 n C n k a k b n − k (a+b)^n=\sum^{n}_{k=0}C^k_na^kb^{n-k} (a+b)n=k=0∑nCnkakbn−k
那么可以推出:
( a x + b y ) n = ∑ k = 0 n C n k ( a x ) k ( b y ) n − k = ∑ k = 0 n ( C n k a k b n − k ) x k y n − k (ax+by)^n=\sum^{n}_{k=0}C^k_n(ax)^k(by)^{n-k}=\sum^{n}_{k=0}(C^k_na^kb^{n-k})x^ky^{n-k} (ax+by)n=k=0∑nCnk(ax)k(by)n−k=k=0∑n(Cnkakbn−k)xkyn−k
二项式定理可以通过数学归纳法证明,但因为个人实力有限 (教练没讲),就不证明了。
例题 3 3 3 :
P1313 [NOIP2011 提高组] 计算系数
用杨辉三角递推求出组合数,直接套用二项式定理计算系数,用快速幂处理 a k b n − k a^kb^{n-k} akbn−k 即可。
#include <bits/stdc++.h>
using namespace std;
long long n,m,k,a,b,c[1010][1010];
long long power(long long a,long long p,long long m)
{long long x=a,ans=1;while(p){if(p%2==1)ans=ans*x%m;p/=2;x=x*x%m;}return ans;
}int main()
{scanf("%lld%lld%lld%lld%lld",&a,&b,&k,&n,&m);c[0][0]=1;for(long long i=1;i<=k;i++)c[i][0]=c[i][i]=1;for(long long i=1;i<=k;i++)for(long long j=1;j<i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%10007;printf("%lld\n",((c[k][m]*power(a,n,10007))*power(b,m,10007))%10007); return 0;
}
例题 4 4 4 :
CF1332E Height All the Same
考虑到可以在一个格子上码上两个方块,易得如果每个格子奇偶性相同,则一定可以到达同样高度。对于任意点对 ( x , y ) (x,y) (x,y),我们可以通过找到一条路,路径上可以互达的两点有一边相邻, x → b → c ⋯ → y x\to b\to c\dots\to y x→b→c⋯→y,每次增加相邻两个点,这样除了 x , y x,y x,y 各自加 1 1 1,其余的点均加 2 2 2,奇偶性不变。
所以,我们每次可以改变两个点的奇偶性。对于 n m nm nm 为奇数的情况,我们一定可以找到一种奇偶性的数有偶数个,每次修改一对为另一种奇偶性。也就是说,对于任意一种初始情况,均可以修改至完全相同。数量为 ( r − l + 1 ) n m (r-l+1)^{nm} (r−l+1)nm。
对于 n m nm nm 为偶数的情况,只有奇偶数个数均为偶数时才满足要求。考虑枚举奇数数量方案数累加,运用乘法原理求出每种情况的方案数。我们先选位置,如果现在有 i i i 个奇数,则有 C n m i C_{nm}^{i} Cnmi 种选法。设 [ l , r ] [l,r] [l,r] 有 a a a 个奇数, b b b 个偶数,则奇数有 a i a^i ai 种方法,偶数有 b n m − i b^{nm-i} bnm−i 种选法。
∑ i = 0 , 2 ∣ i n m C n m i a i b n m − i \sum_{i=0,2\mid i}^{nm}C_{nm}^{i}a^ib^{nm-i} i=0,2∣i∑nmCnmiaibnm−i
看到这个式子,容易联想到二项式定理。但是这个式子不好转化,需要转化为对于每一个 i i i 都有一个计算式。我们考虑用整体减去部分,可是还是不行。顺着这个思路,可以想到利用 − 1 -1 −1 的幂构造摆动数列,当 i i i 为奇数时, ( − 1 ) i (-1)^i (−1)i 刚好为负数,表示减去奇数项;当 i i i 为偶数时, ( − 1 ) i (-1)^i (−1)i 为正数,尽管有重复计算,可是恰好答案中的每种情况算了两遍,最后除以 2 2 2 即可。
( r − l + 1 ) n m − ∑ i = 0 n m ( − 1 ) i C n m i a i b n m − i 2 \frac{(r-l+1)^{nm}-\sum_{i=0}^{nm}(-1)^iC_{nm}^{i}a^ib^{nm-i}}{2} 2(r−l+1)nm−∑i=0nm(−1)iCnmiaibnm−i
直接利用二项式定理进行转化,达到复杂度 O ( log ( n m ) ) O(\log(nm)) O(log(nm))。
( r − l + 1 ) n m − ( b − a ) n m 2 \frac{(r-l+1)^{nm}-(b-a)^{nm}}{2} 2(r−l+1)nm−(b−a)nm
#include <bits/stdc++.h>
using namespace std;
long long n,m,l,r,mod=998244353;
long long power(long long a,long long p)
{long long x=a,ans=1;while(p){if(p%2==1)ans=ans*x%mod;p/=2;x=x*x%mod;}return ans;
}int main()
{scanf("%lld%lld%lld%lld",&n,&m,&l,&r);if(n*m%2==1)printf("%lld",power(r-l+1,n*m));else {long long a=(r-l+1)/2,b=0;if((r-l+1)%2==1&&l%2==1)a++;b=r-l+1-a;printf("%lld",(power(r-l+1,n*m)+power((b-a+mod)%mod,n*m))%mod*499122177%mod);}return 0;
}
Lucas定理
若 p p p 为质数,则有如下式子:
C n m ≡ C ⌊ n / p ⌋ ⌊ m / p ⌋ × C n % p m % p ( m o d p ) C_n^m\equiv C_{\lfloor n/p \rfloor}^{\lfloor m/p \rfloor}\times C_{ n\%p }^{m\%p }(mod\;p) Cnm≡C⌊n/p⌋⌊m/p⌋×Cn%pm%p(modp)
证明可以看文末的博客。
例题 5 5 5 :
P3807 【模板】卢卡斯定理/Lucas 定理
卢卡斯定理模板题,运用卢卡斯定理 C n m ≡ C ⌊ n / p ⌋ ⌊ m / p ⌋ × C n % p m % p ( m o d p ) C_n^m\equiv C_{\lfloor n/p \rfloor}^{\lfloor m/p \rfloor}\times C_{ n\%p }^{m\%p }(mod\;p) Cnm≡C⌊n/p⌋⌊m/p⌋×Cn%pm%p(modp) 把组合数拆成两部分,一部分为 C n % p m % p C_{ n\%p }^{m\%p } Cn%pm%p ,保证了逆元存在,直接用组合求逆元。另一部分 C ⌊ n / p ⌋ ⌊ m / p ⌋ C_{\lfloor n/p \rfloor}^{\lfloor m/p \rfloor} C⌊n/p⌋⌊m/p⌋ 接着递归就行了。所以,只有 p p p 为质数时才能使用 Lucas 定理。
注意三个实现细节:
1 1 1 : m = 0 m=0 m=0 时为递归出口,这里应该返回 1 1 1 而不是 0 0 0 。
2 2 2 :可以预处理出阶乘来降低时间复杂度。
3 3 3 :当求组合数时如果 m > n m>n m>n 特判返回 0 0 0 。
#include <bits/stdc++.h>
using namespace std;
long long t,n,k,m,sum[100010];
long long power(long long a,long long p,long long m)
{long long x=a,ans=1;while(p){if(p%2==1)ans=(x%m*ans%m)%m;p/=2;x=(x%m*x%m)%m;}return ans;
}long long get_c(long long n,long long k,long long m)
{if(k>n)return 0;return ((sum[n]%m*power(sum[k],m-2,m)%m)%m*power(sum[n-k],m-2,m)%m)%m;
}long long lucas(long long n,long long k,long long m)
{if(k==0)return 1;else return (lucas(n/m,k/m,m)%m*get_c(n%m,k%m,m)%m)%m;
}int main()
{scanf("%lld",&t);while(t--){scanf("%lld%lld%lld",&n,&k,&m);sum[0]=1;for(int i=1;i<=m;i++)sum[i]=(sum[i-1]%m*i%m)%m;printf("%d\n",lucas(n+k,k,m));}return 0;
}
全排列问题
全排列问题
对于字符集 X X X,将 X X X 的所有元素的可能排列全部枚举出来,对含有 N N N 个元素的集合 X X X ,排列总个数 S S S 为 :
S = N ! S=N! S=N!
定义一个 1 ∼ n 1\sim n 1∼n 的排列 A A A ,由 1 , 2 … n 1,2\dots n 1,2…n 这 n n n 个数字组成。
有重复元素的排列
有 m 1 m_1 m1 个 1 1 1,有 m 2 m_2 m2 个 2 2 2, … \dots …,有 m k m_k mk 个 k k k,
共 N N N 个元素,排列总个数 S S S 为 :
S = N ! m 1 ! m 2 ! … m k ! S=\frac{N!}{m_1!m_2!\dots m_k!} S=m1!m2!…mk!N!
其他杂题
例题 6 6 6 :
P3197 [HNOI2008]越狱
由于只要有一种相同宗教相邻就会发生越狱,不好求,可以正难则反,用总共的数量减去没有相邻的数量。
对于总共的情况,由于每一个位置都能选择 m m m 个宗教,那么根据乘法原理,总共有 m n m^n mn 种排列方式。
对于没有相邻的情况,第一个位置有 m m m 种选择。由于相邻宗教不相同,那么接下来每个位置就有 m − 1 m-1 m−1 种选择。根据乘法原理,总共有 m ( m − 1 ) n − 1 m(m-1)^{n-1} m(m−1)n−1 种排列方式。
用总共的数量减去不满足的数量,就能得到答案 S S S 了:
S = m n − m ( m − 1 ) n − 1 S=m^n-m(m-1)^{n-1} S=mn−m(m−1)n−1
注意减法取模要先加上模数。
#include <bits/stdc++.h>
using namespace std;
long long m,n,mod=100003;
long long power(long long a,long long p,long long m)
{long long x=a,ans=1;while(p){if(p%2==1)ans=ans*x%m;p/=2;x=x*x%m;}return ans;
}int main()
{scanf("%lld%lld",&m,&n);printf("%lld",((power(m,n,mod)-m*power(m-1,n-1,mod))%mod+mod)%mod);return 0;
}
例题 7 7 7 :
P4821 [中山市选]生成树
由于生成树中没有环,而每个五边形都构成了一个环,所以每个五边形至少需要拆掉一条边。
而一个五角星圈中间的部分也是一个环,也需要拆掉一条边。所以,会有一个五边形被拆掉两条边。
选择被拆掉两条边的五边形有 n n n 种选法,拆掉两条边的五边形必须拆掉其在中间部分的边,剩下 4 4 4 条边可以任意选择一条拆掉。剩下的 n − 1 n-1 n−1 个五边形拆掉哪条边没有限制,每个有 5 5 5 种拆法,根据乘法原理,共有 5 n − 1 5^{n-1} 5n−1 种。
最后根据乘法原理,得到答案 S S S 为:
S = 5 n − 1 4 n S=5^{n-1}4n S=5n−14n
#include <bits/stdc++.h>
using namespace std;
int t,n,mod=2007;
int power(int a,int p,int m)
{int x=a,ans=1;while(p){if(p%2==1)ans=ans*x%m;p/=2;x=x*x%m;}return ans;
}int main()
{scanf("%d",&t);while(t--){scanf("%d",&n);printf("%d\n",4*n%mod*power(5,n-1,mod)%mod);}return 0;
}
递推问题
错排问题
给一个数 n n n,求有多少 1 ∼ n 1\sim n 1∼n 的排列 A A A 满足对于每个 i i i ,都满足 A i ≠ i A_i\ne i Ai=i 。
例如当 n = 3 n=3 n=3 时,满足要求的排列只有 2 , 3 , 1 2,3,1 2,3,1 和 3 , 1 , 2 3,1,2 3,1,2 。
用 a , b , c , d … a,b,c,d\dots a,b,c,d… 表示 n n n 个数字, A , B , C , D … A,B,C,D\dots A,B,C,D… 表示 n n n 个位置( a a a 对应 A A A), 错装的方法总数为记作 f n f_n fn。
假设把 a a a 错装进 B B B 中, 然后接下来我们可以分为两种情况:
1 1 1 : b b b 错装进了 A A A 中
那么问题就变为 c , d … c,d\dots c,d… 个数字(共 n − 2 n-2 n−2 个)放入 C , D … C,D\dots C,D… 这 n − 2 n-2 n−2 个位置时完全装错。由定义得有 f n − 2 f_{n-2} fn−2 种。
2 2 2 : b b b 错装进了除 A A A 之外的一个位置
由于题设中 b b b 不能放入 A A A ,我们可以把 A A A 想象成 B B B ,就相当于将 b , c , d … b,c,d\dots b,c,d… 这 n − 1 n-1 n−1 个数字放入 B , C , D … B,C,D\dots B,C,D… 这 n n n 个位置时完全放错。由定义得有 f n − 1 f_{n-1} fn−1 种。
a a a 错装进 B B B 中,有 f n − 1 + f n − 2 f_{n-1}+f_{n-2} fn−1+fn−2 种, 同样 a a a 错装进 C C C 中也有 f n − 1 + f n − 2 f_{n-1}+f_{n-2} fn−1+fn−2 种 … \dots … 所以根据加法原理,求出 f f f 的递推式为:
f n = ( n − 1 ) ( f n − 1 + f n − 2 ) f_n=(n-1)(f_{n-1}+f_{n-2}) fn=(n−1)(fn−1+fn−2)
例题 8 8 8 :
P4071 [SDOI2016]排列计数
由于序列恰好有 m m m 个位置,使得 a i = i a_i = i ai=i,所以剩下的 n − m n-m n−m 个位置满足 a i ≠ i a_i \ne i ai=i ,就是上文所述的 f n − m f_{n-m} fn−m ,直接线性递推即可。
使得 a i = i a_i = i ai=i 的 m m m 个位置,本身就有 C n m C_{n}^m Cnm 种选法。根据乘法原理,得到答案为:
C n m f n − m C_n^mf_{n-m} Cnmfn−m
注意需要求逆元以及预处理做到 O ( 1 ) O(1) O(1) 回答询问。
#include <bits/stdc++.h>
using namespace std;
long long t,m,n,cuo[1000020],jc[1000020],inv[1000020],mod=1000000007;
long long power(long long a,long long p,long long m)
{long long ans=1,x=a;while(p){if(p%2==1)ans=ans*x%m;p/=2;x=x*x%m;}return ans;
}int main()
{cuo[0]=1;cuo[2]=1;jc[0]=1;jc[1]=1;inv[0]=1;inv[1]=1;for(int i=2;i<=1000010;i++)jc[i]=jc[i-1]*i%mod;for(int i=2;i<=1000010;i++)inv[i]=power(jc[i],mod-2,mod)%mod;for(int i=3;i<=1000010;i++)cuo[i]=(i-1)*(cuo[i-1]+cuo[i-2])%mod;scanf("%lld",&t);for(int i=1;i<=t;i++){scanf("%lld%lld",&n,&m);if(n<m){printf("0\n");continue;}printf("%lld\n",jc[n]*inv[n-m]%mod*inv[m]%mod*cuo[n-m]%mod);}return 0;
}
第二类Stirling数
n n n 个有区别的球放到 m m m 个相同的盒子中,要求无一空盒,其不同的方案数用 S 2 n , m S2_{n,m} S2n,m 表示,称为第二类Stirling数。
设有 n n n 个不同的球,分别用 b 1 , b 2 , … b n b_1,b_2,\dots b_n b1,b2,…bn 表示。 从中取出一个球 b n b_n bn, b n b_n bn的放法有以下两种:
1 1 1 : b n b_n bn 独自占一个盒子
那么剩下的球只能放在 m − 1 m-1 m−1 个盒子中,方案数为 S 2 n − 1 , m − 1 S2_{n-1,m-1} S2n−1,m−1 。
2 2 2 : b n b_n bn 与别的球共占一个盒子
那么可以事先将 b 1 , b 2 , … b n − 1 b_1,b_2,\dots b_{n-1} b1,b2,…bn−1 这 n − 1 n-1 n−1 个球放入 m m m 个盒子中,然后再将球 b n bn bn 可以放入其中一个盒子中,方案数为 m S 2 n − 1 , m mS2_{n-1,m} mS2n−1,m。
根据加法原理,得出第二类Stirling数的递推式:
S 2 n , m = S 2 n − 1 , m − 1 + m S 2 n − 1 , m S2_{n,m}=S2_{n-1,m-1}+mS2_{n-1,m} S2n,m=S2n−1,m−1+mS2n−1,m
例题 9 9 9 :
P1655 小朋友的球
第二类Stirling数板子题,注意需要高精度。
#include <bits/stdc++.h>
using namespace std;
int n,m;
int f[101][101][101];
void huge_int(int na,int nb,int a,int b,int c,int d,int m)
{int flag=0;for(int i=1;i<=100;i++)f[na][nb][i]=f[a][b][i];for(int i=100;i>0;i--){f[na][nb][i]+=f[c][d][i]*m+flag;flag=f[na][nb][i]/10;f[na][nb][i]%=10;}
}void print(int n,int m)
{int now=1;for(now=1;now<=100;now++)if(f[n][m][now]!=0)break;for(int i=now;i<=100;i++)printf("%d",f[n][m][i]);
}int main()
{for(int i=1;i<=100;i++)f[i][1][100]=f[i][i][100]=1;for(int i=1;i<=100;i++)for(int j=1;j<=100;j++)if(!(i==j||j==1))huge_int(i,j,i-1,j-1,i-1,j,j);while(scanf("%d%d",&n,&m)!=-1){if(n<m){printf("0\n");continue;}print(n,m);putchar('\n');}return 0;
}
后记
教练推荐的几篇博客:
lucas定理
不容易系列之(4)——考新郎
相关文章:
【6】组合计数学习笔记
前言 关于今天发现自己连快速幂都忘记怎么写这件事 这篇博客是组合计数基础,由于大部分内容都是 6 6 6 级,所以我就给整个提高级的组合数学评了 6 6 6 级。 组合计数基础 加法原理与乘法原理 加法原理(分类计数原理)&#…...
Ai客服机器人系统源码
我将基于常见的自然语言处理库,用 Python 编写一个简单的 AI 客服机器人功能代码示例,它能处理常见问题并根据用户输入提供相应回复。 import nltk from nltk.chat.util import Chat, reflections # 下载必要的NLTK数据 nltk.download(pun…...
Redis——事务实现以及应用场景
本文介绍Redis事务相关的原理以及知识点,从redis的常用命令出发,深入理解redis在日常工作中的实际场景使用用法。 本文目录 一、Redis事务简介二、事务相关命令三、事务应用场景 一、Redis事务简介 Redis 事务本质上是一个命令队列。用户可以使用MULTI命…...
SpringBoot 第二课(Ⅰ) 整合springmvc(详解)
目录 一、SpringBoot对静态资源的映射规则 1. WebJars 资源访问 2. 静态资源访问 3. 欢迎页配置 二、SpringBoot整合springmvc 概述 Spring MVC组件的自动配置 中央转发器(DispatcherServlet) 控制器(Controller) 视图解…...
Kafka 八股文
一、基础概念 1. Kafka 是什么?它的核心组件有哪些? Kafka 的定义 Kafka 是一个 分布式流处理平台,最初由 LinkedIn 开发,后成为 Apache 顶级项目。它主要用于 高吞吐量的实时数据流处理,支持发布-订阅模式的消息传递…...
OpenHarmony 开源鸿蒙北向开发——3.配置SDK
安装、配置完成之后我们就要配置SDK。 我们创建工程后,点击右上角设置 进入设置 进入OpenHarmony SDK,选择编辑 这里配置一下SDK安装位置 点击完成 这里我们API版本勾选第一个即可 确认安装 勾选接受 这里要等一会 安装完成后,点击完成...
电子工程师转战汽车OEM主机厂之路
文章目录 1 电子工程师2 汽车系统工程师 第一篇分享一个笔者2018年的一个心得文章,回头想想从事汽车行业也小8年了,从懵懂稚嫩到所谓的老油条,也是难忘的经历,希望我的经历对从事电子行业和汽车行业的小伙伴有所帮助。 1 电子工程…...
vulhub Matrix-Breakout
1.下载靶机,打开靶机和kali虚拟机 2.查询kali和靶机ip 3.浏览器访问 访问81端口有登陆界面 4.扫描敏感目录 kali dirb 扫描 一一访问 robot.txt提示我们继续找找,可能是因为我们的字典太小了,我们换个扫描器换个字典试下,利用kali自带的最大…...
Unity3D开发AI桌面精灵/宠物系列 【二】 语音唤醒 ivw 的两种方式-Windows本地或第三方讯飞等
Unity3D 交互式AI桌面宠物开发系列【二】ivw 语音唤醒 该系列主要介绍怎么制作AI桌面宠物的流程,我会从项目开始创建初期到最终可以和AI宠物进行交互为止,项目已经开发完成,我会仔细梳理一下流程,分步讲解。 这篇文章主要讲有关于…...
三月九次前端面试复盘:当场景题成为通关密钥
三月初集中面了包括字节、美团、滴滴在内的9家公司,经历7场技术面2场Leader面后,发现如今的面试逻辑已发生根本转变。这里分享真实经历与题目,供近期求职者参考。 一、面试形态变化:从理论背诵到实战推演 1. 八股文边缘化&#…...
STM32 —— 嵌入式系统、通用计算机系统、物联网三层架构
目录 一、嵌入式系统的概念 二、通用计算机系统与嵌入式系统的比较 用途 硬件 软件 性能与功耗 开发与维护 三、嵌入式系统与物联网的关系 四、物联网的三层架构 1. 感知层(Perception Layer) 2. 网络层(Network Layer) …...
如何选择合适的 AI 模型?(开源 vs 商业 API,应用场景分析)
1. 引言 在 AI 迅猛发展的今天,各类 AI 模型层出不穷,从开源模型(如 DeepSeek、Llama、Qwen)到商业 API(如 OpenAI 的 ChatGPT、Anthropic 的 Claude、Google Gemini),每种方案都有其优势与适用…...
视频对讲系统中,强插和强拆;视频分发功能
强插和强拆 在视频对讲系统中,强插和强拆是两个具有特定功能的操作,具体含义如下: 强插功能:指在视频对讲过程中,具有更高权限的用户或管理员可以强行插入正在进行的通话或视频连接。例如,当小区保安室监控…...
C++输入输出流第一弹:标准输入输出流 详解(带测试代码)
目录 C输入输出流 流的四种状态(重点) 标准输入输出流 标准输入流 逗号表达式 1. 逗号表达式的基本规则 示例 2. 图片中的代码分析 关键点解析 3. 常见误区 误区 1:逗号表达式等同于逻辑与 && 误区 2:忽略输入…...
{瞎掰} 手机安装app问题:app签名,手机 or OS官方商店 其他非官方app源,安全防护 突破限制
以下,在华为安卓系统手机中,在安装app过程中得到的一些可能是错误的经验。 商品化 app 的收钱方式:通过商店来收钱,通过 app 本身提供的注册码功能来收钱,或是其他的收钱方式。 手机安装 app的特点 从官方商店里安装…...
鸿蒙NEXT项目实战-百得知识库05
代码仓地址,大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…...
记录一次,rabbitmq开启stomp插件之后,还是连不上15674端口的问题
原因是装在docker 里面的rabbitmq 没有映射15674端口,需重新删除容器之后重新运行 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -p 15674:15674 -p 1883:1883 -p 15675:15675 rabbitmq:版本号 进入docker容器开启插件 docker exec -it rabbitm…...
黑马node.js教程(nodejs教程)——AJAX-Day01-04.案例_地区查询——查询某个省某个城市所有地区(代码示例)
文章目录 代码示例效果 代码示例 axiosTest.html <!DOCTYPE html> <!-- 文档类型声明,告诉浏览器这是一个HTML5文档 --> <html lang"en"> <!-- HTML根元素,设置文档语言为英语 --><head> <!-- 头部区域&am…...
vue 自制列表,循环滚动
需求人员表示,超过高度的表格内容需要滚动展示,所以效果图如下: 自定义列表样式,主要是通过flex布局,控制 类th 与 类td 的宽度保持一致,标签结构还是参考了table的结构,由thead与tbody包裹tr再…...
【QA】模板方法模式在Qt中有哪些应用?
在 Qt 框架中,模板方法模式(Template Method Pattern)被广泛应用于框架的设计中,通过定义算法骨架并允许子类在不改变结构的情况下重写部分步骤。以下是 Qt 中典型的应用场景及示例: 1. 事件处理(Event Ha…...
图论——kruskal算法
53. 寻宝(第七期模拟笔试) 题目描述 在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。 不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通…...
Windows主机、虚拟机Ubuntu、开发板,三者之间文件互传
以下内容源于日常学习的整理,欢迎交流。 下图是Windows主机、虚拟机Ubuntu、开发者三者之间文件互传的方式示意图: 注意,下面谈及的所有方式,都要求两者的IP地址处于同一网段,涉及到的软件资源见felm。 一、Windows主…...
Flutter Dart 泛型详解
引言 在 Flutter 开发中,Dart 语言的泛型是一项强大且实用的特性。泛型允许我们在定义类、方法或接口时使用类型参数,这样可以编写更加灵活、可复用且类型安全的代码。下面将详细介绍 Dart 泛型的各个方面,并结合代码示例进行说明。 1. 泛型…...
Windows Docker 报错: has no HTTPS proxy,换源
pull python 3.7报错: 尝试拉取Docker 测试库hello world也失败 尝试使用临时镜像源,可以成功拉取: sudo docker pull docker.m.daocloud.io/hello-world说明确实是网络问题,需要配置镜像源,为了方便,在d…...
Java:Arrays类:操作数组的工具类
文章目录 Arrays类常见方法SetAll(); 代码排序如果数组中存储的是自定义对象 Arrays类 常见方法 SetAll(); 注意: 不能用新的数组接是因为修改的是原数组,所以完了要输出原数组发现会产生变化参数是数组下标变成灰色是因为还能简化(Lambda…...
【面试场景题-Redis中String类型和map类型的区别】
今天在面试中碰到一个场景题:在 Redis 中存储 100 万用户数据时,使用 String 类型和 Hash(Map)类型的主要区别是什么?体现在以下几个方面: 1. 存储结构与内存占用 String 类型 存储方式:每个用…...
List附加对象
List里面的某个对象需要修改,赋值 可以使用ALL或者ForEach,All的话,不能直接使用赋值对象只能赋值对象的某个字段 static void Main(string[] args){List<UserData> UserDatas new List<UserData>{new UserData { Id 1, Name …...
VLLM专题(三十六)—自动前缀缓存
PagedAttention 的核心思想是将每个请求的 KV 缓存划分为 KV 块。每个块包含固定数量的标记(tokens)对应的注意力键(keys)和值(values)。PagedAttention 算法允许将这些块存储在非连续的物理内存中,从而通过按需分配内存来消除内存碎片。 为了自动缓存 KV 缓存,我们利…...
相机光学(四十七)——相纸材质
1. 光面相纸 光面相纸表面光滑,亮度高,反光性好,能够呈现出清晰、鲜艳的图像效果,适合用于表现色彩艳丽、反差要求较高的题材,如产品照、艺术照和风景照。然而,这种相纸容易沾上指纹和灰尘。 2. 绒面相纸…...
数据表100多字段如何写mapper文件的xml
编写一个包含100多个字段的插入语句通常涉及到使用<mapper>标签来定义映射规则,特别是在使用MyBatis这样的持久层框架时。 1. 定义<mapper>命名空间 order表 <mapper namespace"com.example.mapper.orderMapper"><!-- 插入语句 --…...
