1.组合数学的基本定义与基础题型

很水,可以选择性阅读。

例题:洛谷 P5135 painting
给定一个网格,每一列一个元素涂成黑色,求单调下降与单调不升的方案数,对 109+710^9+7109+7 取模。
单调下降 :显然 CnmC _n^mCnm​
单调不升 :显然 Cn+m–1mC_{n + m – 1}^mCn+m–1m​
考虑位置 ai+ia_i + iai​+i 是单调的,且在 [2,n+m][ 2 , n + m ][2,n+m] 区间内,选 m 种,共有 Cn+m–1mC_{n + m – 1}^mCn+m–1m​ 种选择方式。

#include<iostream>
#include<cstdio>
#define MAXN 1000005using namespace std;const int mod=1e9+7;int inv[MAXN];int C(long long n,long long m){if(n<m) return 0;int ans=1;for(long long i=1;i<=m;i++)ans=1ll*(n-i+1)%mod*inv[i]%mod*ans%mod;return ans;
}void solve(){long long n,m,opt;cin >> n >> m >> opt;if(opt==1){cout << C(n,m) << endl;}else{cout << C(n+m-1,m) << endl;}
}int main(){inv[1]=1;for(int i=2;i<MAXN;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;int T; cin >> T;while(T--) solve();return 0;
}

例题:洛谷 P8432 「WHOI-2」ぽかぽかの星

一场有两道大模拟的公开赛的签到题。

求满足以下条件的长度为 nnn 的数列的数量,对 109+710^9+7109+7 取模:

  • 0<a1≤a2≤a3⋯≤an≤k0<a_1\leq a_2\leq a_3\dots \leq a_n\leq k0<a1​≤a2​≤a3​⋯≤an​≤k。
  • ∀i≠j,ai+aj≠k+1\forall i\not = j,a_i+a_j\not = k+1∀i=j,ai​+aj​=k+1。

分 kkk 奇偶性讨论,将两个不能同时出现的数放在一组。

kkk 为偶数时,有 k2\frac{k}{2}2k​ 组,枚举选的组数,再计算对于所有组数的答案。
即:
∑i=1k2Ck2iCn−1i−12i\sum_{i = 1}^{\frac{k}{2}} C_{\frac{k}{2}}^iC_{n - 1}^{i - 1}2^ii=1∑2k​​C2k​i​Cn−1i−1​2i
kkk 为奇数时,需要再计算 k+12\frac{k+1}{2}2k+1​ 是否出现过的答案。
即:
∑i=1k2Ck2iCn−1i−12i+∑i=1k2Ck2iCn−2i−12i\sum_{i = 1}^{\frac{k}{2}} {C_{\frac{k}{2}}^iC_{n - 1}^{i - 1}2^i} +\sum_{i = 1}^{\frac{k}{2}} C_{\frac{k}{2}}^iC_{n - 2}^{i - 1}2^ii=1∑2k​​C2k​i​Cn−1i−1​2i+i=1∑2k​​C2k​i​Cn−2i−1​2i

#include<iostream>
#include<cstdio>
#define MAXN 5000005using namespace std;const int mod=1e9+7;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int fac[MAXN],invfac[MAXN],base2[MAXN];int C(int n,int m){if(n<m) return 0;return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}void solve(){int n,k,ans=0;cin >> n >> k;if(n==1){cout << k << endl;return;}if(k%2==1){for(int i=1;i<=k/2;i++){ans=(ans+1ll*C(k/2,i)*C(n-1,i-1)%mod*base2[i]%mod)%mod;ans=(ans+1ll*C(k/2,i)*C(n-2,i-1)%mod*base2[i]%mod)%mod;}cout << ans << endl;}else{for(int i=1;i<=k/2;i++){ans=(ans+1ll*C(k/2,i)*C(n-1,i-1)%mod*base2[i]%mod)%mod;}cout << ans << endl;}
}int main(){fac[0]=base2[0]=1;for(int i=1;i<MAXN;i++) fac[i]=1ll*fac[i-1]*i%mod,base2[i]=(2ll*base2[i-1])%mod;invfac[MAXN-1]=Fp(fac[MAXN-1],mod-2);for(int i=MAXN-2;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;int T; cin >> T;while(T--) solve();return 0;
}

例题:CF294C Shaass and Lights

有 nnn 盏灯,其中亮了 mmm 盏,现每次可点亮一盏与亮的灯相邻的灯,求将所有的灯都点亮的方案数。

考虑初始时亮的灯把序列分成了 m+1m + 1m+1 段,我们在每次操作时,选择其中的一段点亮一盏灯。根据可重集排列的性质,有:
ans=(n−m)!∏i=1m+1leni!ans = \frac{(n - m)!}{\prod_{i = 1}^{m + 1} len_i!}ans=∏i=1m+1​leni​!(n−m)!​

其中 lenilen_ileni​ 为分离出的第 iii 个区间的长度。

然后再考虑对于除最左侧的段和最右侧的段以外,其余的段在每次的选择时都有两种方案,选择最左侧的一盏灯点亮,或者选择最右侧的一盏灯点亮,因此,共有 2n−m−len1−lenm+12^{n - m - len_1 - len_{m + 1}}2n−m−len1​−lenm+1​ 种选择方式。

相乘即得最终答案。

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define MAXN 100005using namespace std;const int mod=1e9+7;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int n,m,base2[MAXN],fac[MAXN],invfac[MAXN],a[MAXN];bool flag[MAXN];int main(){ios :: sync_with_stdio(false);cin.tie(nullptr); cout.tie(nullptr);cin >> n >> m;base2[0]=fac[0]=1;for(int i=1;i<=m;i++) cin >> a[i];stable_sort(a+1,a+m+1);for(int i=1;i<=n;i++){fac[i]=1ll*fac[i-1]*i%mod;base2[i]=(base2[i-1]+base2[i-1])%mod;}invfac[n]=Fp(fac[n],mod-2);for(int i=n-1;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;int ans=fac[n-m];for(int i=1;i<=m;i++){int tmp=a[i]-a[i-1]-1;if(tmp==0) continue;ans=1ll*ans*invfac[tmp]%mod;if(i!=1) ans=1ll*ans*base2[tmp-1]%mod;}if(a[m]!=n) ans=1ll*ans*invfac[n-a[m]]%mod;cout << ans << endl;return 0;
}

2.容斥原理在组合数学中的思想及应用

例题:洛谷 P5339 [TJOI2019]唱、跳、rap和篮球
有 AAA 个人喜欢唱,BBB 个人喜欢跳, CCC 个人喜欢 rap , DDD 个人喜欢篮球,选 NNN 个人排成一列,如果连续的 444 个人分别喜欢唱,跳, rap ,篮球,则他们会讨论蔡徐坤,现需要求出没有人讨论蔡徐坤的排列方案数,有同样爱好的人被视为同样的。

N≤1000,A,B,C,D≤500N\leq1000,A,B,C,D\leq500N≤1000,A,B,C,D≤500 。

定义 f(n,a,b,c,d)f(n,a,b,c,d)f(n,a,b,c,d) 为 aaa 个喜欢唱, bbb 个喜欢跳, ccc 个喜欢 rap , ddd 个喜欢篮球的人任意排列成 nnn 个人的方案数,对 998244353998244353998244353 取模。

这个东西显然等于

∑i=1a∑j=1b∑k=1c∑l=1d[i+j+k+l=n]×n!i!j!k!l!\sum_{i = 1}^{a}\sum_{j = 1}^{b}\sum_{k = 1}^{c}\sum_{l = 1}^{d}[i + j + k + l = n] \times \frac{n!}{i!j!k!l!}i=1∑a​j=1∑b​k=1∑c​l=1∑d​[i+j+k+l=n]×i!j!k!l!n!​

把 n!n!n! 提出来,里面很显然能 NTT ,O(nlog⁡n)O(n\log n)O(nlogn) 能求。

之后考虑容斥,有:

ans=∑i=0⌊n4⌋(−1)iCn−3ii×f(N−4i,A−i,B−i,C−i,D−i)ans = \sum_{i = 0}^{\lfloor\frac{n}{4}\rfloor}(-1)^i C_{n - 3i}^{i} \times f(N - 4i , A - i , B - i , C - i , D - i)ans=i=0∑⌊4n​⌋​(−1)iCn−3ii​×f(N−4i,A−i,B−i,C−i,D−i)

考虑枚举至少有 iii 组人讨论蔡徐坤,剩下的人任意排列的方案。我们把连续 444 个讨论蔡徐坤的人看成一个蔡徐坤,总共 n−3in - 3in−3i 个人里面挑出 iii 个人当蔡徐坤即可。

#include<iostream>
#include<cstdio>
#define MAXN 2005using namespace std;const int mod=998244353;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int n,A,B,C,D,a[MAXN<<2],b[MAXN<<2],c[MAXN<<2],d[MAXN<<2],rev[MAXN<<2];int fac[MAXN],invfac[MAXN];void NTT(int * a,int lim,int flag){for(int i=0;i<lim;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int mid=1;mid<lim;mid<<=1){int tmp=Fp(flag==1?3:Fp(3,mod-2),(mod-1)/(mid<<1));for(int i=0;i<lim;i+=(mid<<1)){int x=1;for(int j=0;j<mid;j++,x=1ll*x*tmp%mod){int t1=a[i+j],t2=a[i+mid+j];a[i+j]=(t1+1ll*x*t2%mod)%mod;a[i+mid+j]=(t1-1ll*x*t2%mod+mod)%mod;}}}if(flag==-1){int inv=Fp(lim,mod-2);for(int i=0;i<lim;i++) a[i]=1ll*a[i]*inv%mod;}
}int C_(int n,int m){if(n<m) return 0;return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}int main(){cin >> n >> A >> B >> C >> D;fac[0]=1;for(int i=1;i<MAXN;i++) fac[i]=1ll*fac[i-1]*i%mod;invfac[MAXN-1]=Fp(fac[MAXN-1],mod-2);for(int i=MAXN-2;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;int ans=0;for(int i=0;i<=n/4&&i<=A&&i<=B&&i<=C&&i<=D;i++){int lim=1,l=0;while(lim<=A+B+C+D-4*i) lim<<=1,l++;for(int j=0;j<lim;j++){rev[j]=(rev[j>>1]>>1)|((j&1)<<l-1);if(j<=A-i) a[j]=invfac[j];else a[j]=0;if(j<=B-i) b[j]=invfac[j];else b[j]=0;if(j<=C-i) c[j]=invfac[j];else c[j]=0;if(j<=D-i) d[j]=invfac[j];else d[j]=0;}NTT(a,lim,1); NTT(b,lim,1); NTT(c,lim,1); NTT(d,lim,1);for(int i=0;i<lim;i++) a[i]=1ll*a[i]*b[i]%mod*c[i]%mod*d[i]%mod;NTT(a,lim,-1);int tmpans=1ll*a[n-4*i]*fac[n-4*i]%mod*C_(n-3*i,i)%mod;if(i&1) ans=(ans-tmpans+mod)%mod;else ans=(ans+tmpans)%mod;}cout << ans << endl;return 0;
}

例题:洛谷 P6295 有标号DAG计数
分别求由 1−n1 - n1−n 个点弱联通 DAG 的个数,对 998244353998244353998244353 取模, n≤105n\leq10^5n≤105 。
(本来不打算讲的,但既然发的资料里有就讲吧)
首先,考虑不要求弱联通的情况
考虑容斥,设函数 f(x)f(x)f(x) 为由 xxx 个点组成的 DAG 的数量,有:

f(n)=∑i=1n(−1)i−1×Cni×f(n−i)×2i×(n−i)f(n) = \sum_{i = 1}^n (-1)^{i - 1}\times C_n^i \times f(n - i) \times 2^{i \times (n - i)}f(n)=i=1∑n​(−1)i−1×Cni​×f(n−i)×2i×(n−i)

考虑组合意义其实是显然的,枚举至少有多少个出度为 000 的节点,再容斥一下就做完了,但是因为我们的重点在容斥原理,所以再详细说明一下。

我们考虑,选出 iii 个出度为 000 的节点时,剩下的节点仍然构成一个规模为 n−in - in−i 的 DAG ,之后再考虑这两部分的关系,我们既然已经钦定了 n−in - in−i 个点所形成的 DAG 的形态,那么,连接在这些点之间的边就是确定的,而可能造成不同情况贡献的答案必然在这两部分之间,那么,也就意味着,目前我们拥有选择空间的边总共有 i×(n−i)i \times (n - i)i×(n−i) 条,这其中的每一条都有连边与不连边两种方式可供选择。此时,我们保证了构造出的 DAG 至少有 iii 个出度为 000 的节点,将 iii 从 111 枚举到 nnn ,再容斥一下,就能得出上式。

O(nlog⁡n)O(n\log n)O(nlogn) 暴力转移显然,不再赘述,我们考虑优化。

考虑 CniC_n^iCni​ 摆出来了,不妨凑个 EGF 形式。

f(n)=∑i=1n(−1)i−1×Cni×f(n−i)×2i×(n−i)f(n) = \sum_{i = 1}^n (-1)^{i - 1}\times C_n^i \times f(n - i) \times 2^{i \times (n - i)}f(n)=i=1∑n​(−1)i−1×Cni​×f(n−i)×2i×(n−i)
=∑i=1n(−1)i−1×Cni×f(n−i)×2Cn2−Ci2−Cn−i2= \sum_{i = 1}^n (-1)^{i - 1}\times C_n^i \times f(n - i) \times 2^{C_n^2 - C_i^2 - C_{n - i}^2}=i=1∑n​(−1)i−1×Cni​×f(n−i)×2Cn2​−Ci2​−Cn−i2​
=∑i=1n(−1)i−1×Cni×f(n−i)×2Cn22Ci2×2Cn−i2= \sum_{i = 1}^n (-1)^{i - 1}\times C_n^i \times f(n - i) \times \frac{2^{C_n^2}}{2^{C_i^2}\times 2^{C_{n - i}^2}}=i=1∑n​(−1)i−1×Cni​×f(n−i)×2Ci2​×2Cn−i2​2Cn2​​
=∑i=1n(−1)i−1×n!i!×(n−i)!×f(n−i)×2Cn22Ci2×2Cn−i2= \sum_{i = 1}^n (-1)^{i - 1}\times \frac{n!}{i!\times (n - i)!} \times f(n - i) \times \frac{2^{C_n^2}}{2^{C_i^2}\times 2^{C_{n - i}^2}}=i=1∑n​(−1)i−1×i!×(n−i)!n!​×f(n−i)×2Ci2​×2Cn−i2​2Cn2​​
=2Cn2×n!×∑i=1n(−1)i−1i!×2Ci2×f(n−i)(n−i)!×2Cn−i2= 2^{C_n^2} \times n! \times \sum_{i = 1}^n \frac{(-1)^{i - 1}}{i!\times 2^{C_i^2}}\times \frac{f(n - i)}{(n - i)! \times 2^{C_{n - i}^2}}=2Cn2​×n!×i=1∑n​i!×2Ci2​(−1)i−1​×(n−i)!×2Cn−i2​f(n−i)​

这样卷积形式就被我们搞出来了,同时还能发现一些优秀的性质,即:
f(n)2Cn2×n!=∑i=1n(−1)i−1i!×2Ci2×f(n−i)(n−i)!×2Cn−i2\frac{f(n)}{2^{C_n^2}\times n!} = \sum_{i = 1}^n \frac{(-1)^{i - 1}}{i!\times 2^{C_i^2}}\times \frac{f(n - i)}{(n - i)! \times 2^{C_{n - i}^2}}2Cn2​×n!f(n)​=i=1∑n​i!×2Ci2​(−1)i−1​×(n−i)!×2Cn−i2​f(n−i)​
左侧的式子和卷积的右半边的式子是一样的。

定义生成函数:
F(x)=∑if(i)2Ci2×i!F(x) = \sum_i \frac{f(i)}{2^{C_i^2}\times i!} F(x)=i∑​2Ci2​×i!f(i)​
G(x)=∑i(−1)i−1i!×2Ci2G(x) = \sum_i \frac{(-1)^{i - 1}}{i! \times 2^{C_i^2}}G(x)=i∑​i!×2Ci2​(−1)i−1​
F(x)=F(x)×G(x)+f(0)=F(x)×G(x)+1F(x) = F(x) \times G(x) + f(0) = F(x) \times G(x) + 1F(x)=F(x)×G(x)+f(0)=F(x)×G(x)+1

根据初中因式分解知识:
(1−G(x))×F(x)=1,F(x)=11−G(x)(1 - G(x))\times F(x) = 1,F(x) = \frac{1}{1 - G(x)}(1−G(x))×F(x)=1,F(x)=1−G(x)1​

F(x)F(x)F(x) 可以求,也就意味着现在 f(x)f(x)f(x) 也可以求出来。

然后我们再考虑弱连通图与一般图间的关系。

这里有一个结论:定义 A(x)A(x)A(x) 为一般图的 EGF ,B(x)B(x)B(x) 为弱连通图的 EGF ,则 A(x)=exp⁡(B(x))A(x) = \exp (B(x))A(x)=exp(B(x)) ,设 f(x)f(x)f(x) 的 EGF 为 F′(x)F'(x)F′(x) ,ln⁡(F′(x))\ln (F'(x))ln(F′(x)) 就是我们想要的答案。

虽然大家都知道这个结论,但是我们需要证明一下:

首先,定义在一个弱连通图的大小为 iii 的点集中的答案为 f(i)f(i)f(i) ,在一个由 iii 个大小总和为 jjj 的弱连通点集所组成的点集中的答案为 Fi(j)F_{i}(j)Fi​(j) 。

则:
Fn(m)=1n∑i=0mCmi×Fn−1(m−i)×f(i)F_{n}(m) = \frac{1}{n} \sum_{i = 0}^mC_m^i \times F_{n - 1}(m - i) \times f(i)Fn​(m)=n1​i=0∑m​Cmi​×Fn−1​(m−i)×f(i)

我们设 Gn(x)G_n(x)Gn​(x) 为 Fn(x)F_n(x)Fn​(x) 的 EGF ,H(x)H(x)H(x) 为 f(x)f(x)f(x) 的 EGF 。
很显然这是个用 EGF 卷积的形式,即:
Gn=Gn−1×1n×H=Hnn!G_n = G_{n - 1} \times \frac{1}{n} \times H = \frac{H^n}{n!}Gn​=Gn−1​×n1​×H=n!Hn​
可以发现这样就变成了 exp⁡(H)\exp (H)exp(H) 的泰勒展开形式,证毕。

代码就是一次多项式求逆和多项式 ln⁡\lnln ,直接把封装好的板子拿来用就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 100005using namespace std;const int mod=998244353;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int rev[MAXN<<2];void NTT(int * a,int lim,int flag){for(int i=0;i<lim;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int mid=1;mid<lim;mid<<=1){int tmp=Fp(flag==1?3:Fp(3,mod-2),(mod-1)/(mid<<1));for(int i=0;i<lim;i+=(mid<<1)){int x=1;for(int j=0;j<mid;j++,x=1ll*x*tmp%mod){int t1=a[i+j],t2=a[i+mid+j];a[i+j]=(t1+1ll*x*t2%mod)%mod;a[i+mid+j]=(t1-1ll*x*t2%mod+mod)%mod;}}}if(flag==-1){int inv=Fp(lim,mod-2);for(int i=0;i<lim;i++) a[i]=1ll*a[i]*inv%mod;}
}int tmp[MAXN<<2];void getinv(int deg,int * a,int * b){if(deg==1) return (void) (b[0]=Fp(a[0],mod-2));getinv(deg+1>>1,a,b);int lim=1,l=0;while(lim<=deg+deg) lim<<=1,l++;for(int i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);for(int i=0;i<deg;i++) tmp[i]=a[i];for(int i=deg;i<lim;i++) tmp[i]=0;NTT(tmp,lim,1); NTT(b,lim,1);for(int i=0;i<lim;i++)b[i]=(2ll*b[i]%mod+mod-1ll*tmp[i]*b[i]%mod*b[i]%mod)%mod;NTT(b,lim,-1);for(int i=deg;i<lim;i++) b[i]=0;
}void Derivation(int * a,int * b,int len){for(int i=1;i<len;i++) b[i-1]=1ll*i*a[i]%mod;b[len-1]=0;
}void Integration(int * a,int * b,int len){b[0]=0;for(int i=1;i<len;i++) b[i]=1ll*a[i-1]*Fp(i,mod-2)%mod;
}int X[MAXN<<2],Y[MAXN<<2];void get_Ln(int * a,int * b,int len){Derivation(a,X,len);getinv(len,a,Y);int lim=1,l=0;while(lim<=len+len) lim<<=1,l++;for(int i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);NTT(X,lim,1); NTT(Y,lim,1);for(int i=0;i<lim;i++) X[i]=1ll*X[i]*Y[i]%mod;NTT(X,lim,-1);Integration(X,b,len);
}int a[MAXN<<2],b[MAXN<<2],c[MAXN<<2],fac[MAXN],invfac[MAXN];int main(){int n; cin >> n;fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;invfac[n]=Fp(fac[n],mod-2);for(int i=n-1;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;a[0]=1;for(int i=1;i<=n;i++){a[i]=1ll*invfac[i]*Fp(Fp(2,1ll*(1ll*i*(i-1)/2ll)%(mod-1)),mod-2)%mod;if(i&1) a[i]=mod-a[i];}getinv(n+1,a,b);for(int i=0;i<=n;i++) b[i]=1ll*Fp(2,1ll*(1ll*i*(i-1)/2ll)%(mod-1))*b[i]%mod;get_Ln(b,c,n+1);for(int i=1;i<=n;i++) cout << 1ll*c[i]*fac[i]%mod << '\n';return 0;
}

3.二项式反演与广义容斥基础

二项式反演:
形式 111 :
若:
f(x)=∑i=0xCxi×g(i)f(x) = \sum_{i = 0}^xC_x^i\times g(i)f(x)=i=0∑x​Cxi​×g(i)
则:
g(x)=∑i=0x(−1)x−i×Cni×f(i)g(x) = \sum_{i = 0}^x(-1)^{x - i}\times C_n^i\times f(i)g(x)=i=0∑x​(−1)x−i×Cni​×f(i)

证明:
考虑把 g(x)g(x)g(x) 带进去
有:
f(x)=∑i=0xCxi×g(i)=∑i=0xCxi×∑j=0i(−1)i−j×Cij×f(j)f(x) = \sum_{i = 0}^xC_x^i\times g(i) = \sum_{i = 0}^xC_x^i\times \sum_{j = 0}^i(-1)^{i - j}\times C_i^j \times f(j)f(x)=i=0∑x​Cxi​×g(i)=i=0∑x​Cxi​×j=0∑i​(−1)i−j×Cij​×f(j)

f(x)=∑j=0xf(j)∑i=jxCxi×Cij×(−1)i−jf(x) = \sum_{j = 0}^xf(j)\sum_{i = j}^xC_x^i\times C_i^j\times (-1)^{i - j}f(x)=j=0∑x​f(j)i=j∑x​Cxi​×Cij​×(−1)i−j

f(x)=∑j=0xf(j)∑i=jxCxj×Cx−ji−j×(−1)i−jf(x) = \sum_{j = 0}^xf(j)\sum_{i = j}^xC_x^j\times C_{x - j}^{i - j}\times (-1)^{i - j}f(x)=j=0∑x​f(j)i=j∑x​Cxj​×Cx−ji−j​×(−1)i−j

f(x)=∑j=0xf(j)×Cxj∑t=0x−jCx−jt×(−1)tf(x) = \sum_{j = 0}^xf(j)\times C_x^j \sum_{t = 0}^{x - j}C_{x - j}^{t}\times (-1)^tf(x)=j=0∑x​f(j)×Cxj​t=0∑x−j​Cx−jt​×(−1)t

当 x≠jx \not=jx=j 时,很显然,由二项式定理,后面那堆东西是等于 000 的,否则等于 111 。
证毕。

很显然可以发现枚举不一定要从 000 开始,从任意位置开始枚举都满足这个式子。

形式 222 :
若:
f(x)=∑i=xnCix×g(i)f(x) = \sum_{i = x}^n C_i^x\times g(i)f(x)=i=x∑n​Cix​×g(i)

则:
g(x)=∑i=xn(−1)i−x×Cix×f(i)g(x) = \sum_{i = x}^n (-1)^{i - x}\times C_i^x\times f(i)g(x)=i=x∑n​(−1)i−x×Cix​×f(i)

将 g(x)g(x)g(x) 带入:

f(x)=∑i=xnCix×∑j=in(−1)j−i×Cji×f(j)f(x) = \sum_{i = x}^n C_i^x\times \sum_{j = i}^n(-1)^{j - i}\times C_j^i\times f(j)f(x)=i=x∑n​Cix​×j=i∑n​(−1)j−i×Cji​×f(j)

f(x)=∑j=xnf(j)∑i=xj(−1)j−i×Cji×Cixf(x) = \sum_{j = x}^nf(j)\sum_{i = x}^j(-1)^{j - i}\times C_j^i\times C_i^xf(x)=j=x∑n​f(j)i=x∑j​(−1)j−i×Cji​×Cix​

f(x)=∑j=xnf(j)×Cjx∑i=xjCj−xi−x×(−1)j−if(x) = \sum_{j = x}^nf(j)\times C_j^x\sum_{i = x}^jC_{j - x}^{i - x}\times (-1)^{j - i}f(x)=j=x∑n​f(j)×Cjx​i=x∑j​Cj−xi−x​×(−1)j−i

f(x)=∑j=xnf(j)×Cjx∑i=xjCj−xj−i×(−1)j−if(x) = \sum_{j = x}^nf(j)\times C_j^x\sum_{i = x}^jC_{j - x}^{j - i}\times (-1)^{j - i}f(x)=j=x∑n​f(j)×Cjx​i=x∑j​Cj−xj−i​×(−1)j−i

f(x)=∑j=xnf(j)×Cjx∑t=0j−xCj−xt×(−1)tf(x) = \sum_{j = x}^nf(j)\times C_j^x\sum_{t = 0}^{j - x}C_{j - x}^{t}\times (-1)^tf(x)=j=x∑n​f(j)×Cjx​t=0∑j−x​Cj−xt​×(−1)t

与形式 111 同理,证毕。

我们考虑这样一件事情,如果 f(x)f(x)f(x) 为至少 xxx 个位置满足条件的方案数,g(x)g(x)g(x) 为恰好 xxx 个位置满足条件的方案数,这个形式刚好和二项式反演是具有一致性的。

例题:洛谷 P4859 已经没有什么好害怕的了

给定长度为 nnn 的不重序列 a,ba,ba,b ,求将 a,ba,ba,b 任意排列,使得其中 ai>bia_i > b_iai​>bi​ 的位置的个数比 bi>aib_i > a_ibi​>ai​ 的个数多 kkk 个的方案数, n≤2000n\leq2000n≤2000 。

令 k=n+k2k = \frac{n+k}{2}k=2n+k​ 。

先将 a,ba,ba,b 排序。

设 dpi,jdp_{i,j}dpi,j​ 为 aaa 的前 iii 个元素中,有 jjj 个满足匹配的 bbb 中元素更小的条件的选择方案数,则有 dpi,j=dpi−1,j+dpi−1,j−1×(numi−j+1)dp_{i,j} = dp_{i - 1,j} + dp_{i - 1,j - 1}\times (num_i - j + 1)dpi,j​=dpi−1,j​+dpi−1,j−1​×(numi​−j+1) ,其中 numinum_inumi​ 为对于第 iii 个位置满足匹配的 bbb 中元素个数。(转移很显然,考虑第 iii 位不匹配或匹配之前未被选过的任意一个元素)。

然后我们设 f(x)f(x)f(x) 为至少满足 xxx 个单调关系的方案数,则 f(x)=dpn,x×(n−x)!f(x) = dp_{n,x} \times (n - x)!f(x)=dpn,x​×(n−x)! 。设 g(x)g(x)g(x) 为恰好满足 xxx 个单调关系的方案数。

由二项式反演,可得:
g(k)=∑i=kn(−1)i−k×Cik×f(k)g(k) = \sum_{i = k}^n(-1)^{i - k}\times C_i^k\times f(k)g(k)=i=k∑n​(−1)i−k×Cik​×f(k)

直接输出 g(k)g(k)g(k) 即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 2005using namespace std;const int mod=1e9+9;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int a[MAXN],b[MAXN],n,k,dp[MAXN][MAXN],fac[MAXN],invfac[MAXN],f[MAXN];int C(int n,int m){if(n<m) return 0;return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}int main(){cin >> n >> k;if(n+k&1) return cout << 0 << endl,0;k=n+k>>1;fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;invfac[n]=Fp(fac[n],mod-2);for(int i=n-1;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;for(int i=1;i<=n;i++) cin >> a[i]; sort(a+1,a+n+1);for(int i=1;i<=n;i++) cin >> b[i]; sort(b+1,b+n+1);dp[0][0]=1;for(int i=1;i<=n;i++){dp[i][0]=1;for(int j=1;j<=i;j++){int rb=lower_bound(b+1,b+n+1,a[i])-b-1;dp[i][j]=dp[i-1][j];if(rb>=j) (dp[i][j]+=1ll*dp[i-1][j-1]*(rb-j+1)%mod)%=mod;}}for(int i=1;i<=n;i++) f[i]=1ll*dp[n][i]*fac[n-i]%mod;int ans=0;for(int i=k;i<=n;i++){int x=1ll*C(i,k)*f[i]%mod;if(i-k&1) ans=(ans-x+mod)%mod;else ans=(ans+x)%mod;}cout << ans << endl;return 0;
}

例题:洛谷 P4491 [HAOI2018] 染色
给定 n,m,sn,m,sn,m,s ,长度为 nnn 的序列, mmm 种颜色染色,求对于所有 k∈[0,m]k\in[ 0 , m ]k∈[0,m] ,恰好 kkk 种颜色出现 sss 次的方案数。n≤107,m≤105n\leq10^7,m\leq10^5n≤107,m≤105。

设 f(i)f(i)f(i) 为至少 iii 种颜色出现恰好 sss 次的方案数,则有:
f(i)=Cmin!(m−i)n−sis!(n−si)!f(i) = C_m^i\frac{n!(m - i)^{n - si}}{s!(n - si)!}f(i)=Cmi​s!(n−si)!n!(m−i)n−si​

选择 iii 种颜色,此时将整体染色方式看成一个 i+1i + 1i+1 种颜色的可重集排列,再将除这 iii 种颜色以外的颜色的方案数乘上即可。

枚举上界不重要,始终枚举到 mmm 即可。

由二项式反演,设恰好 iii 种颜色出现恰好 sss 次的方案数为 g(i)g(i)g(i) ,则有:
g(i)=∑j=im(−1)j−i×Cij×f(j)g(i) = \sum_{j = i}^m(-1)^{j - i}\times C_i^j\times f(j)g(i)=j=i∑m​(−1)j−i×Cij​×f(j)
=∑j=im(−1)j−ij!i!(j−i)!f(j)= \sum_{j = i}^m(-1)^{j - i}\frac{j!}{i!(j - i)!}f(j)=j=i∑m​(−1)j−ii!(j−i)!j!​f(j)
=1i!∑j=im(−1)j−i(j−i)!×f(j)j!=\frac{1}{i!}\sum_{j = i}^m\frac{(-1)^{j - i}}{(j - i)!}\times f(j)j!=i!1​j=i∑m​(j−i)!(−1)j−i​×f(j)j!
=1i!∑t=0m(−1)t(t)!f(t+i)(t+i)!=\frac{1}{i!}\sum_{t = 0}^m\frac{(-1)^{t}}{(t)!}f(t + i)(t + i)!=i!1​t=0∑m​(t)!(−1)t​f(t+i)(t+i)!

设 A(x)=(−1)m−x(m−x)!,B(x)=f(x)x!A(x) = \frac{(-1)^{m - x}}{(m - x)!},B(x) = f(x)x!A(x)=(m−x)!(−1)m−x​,B(x)=f(x)x! ,第 iii 项答案为 [xm+i](A∗B)[x^{m + i}](A * B)[xm+i](A∗B) 。

注意边界条件。

#include<iostream>
#include<cstdio>
#define MAXN 100005
#define MAXNN 10000005using namespace std;const int mod=1004535809;int n,m,s,w[MAXN];int a[MAXN<<2],b[MAXN<<2],rev[MAXN<<2],fac[MAXNN],invfac[MAXNN];int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int C(int n,int m){if(n<m) return 0;return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}void NTT(int * a,int lim,int flag){for(int i=0;i<lim;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int mid=1;mid<lim;mid<<=1){int tmp=Fp(flag==1?3:Fp(3,mod-2),(mod-1)/(mid<<1));for(int i=0;i<lim;i+=(mid<<1)){int x=1;for(int j=0;j<mid;j++,x=1ll*x*tmp%mod){int t1=a[i+j],t2=a[i+mid+j];a[i+j]=(t1+1ll*x*t2%mod)%mod;a[i+mid+j]=(t1-1ll*x*t2%mod+mod)%mod;}}}if(flag==-1){int inv=Fp(lim,mod-2);for(int i=0;i<lim;i++) a[i]=1ll*a[i]*inv%mod;}
}int main(){cin >> n >> m >> s;for(int i=0;i<=m;i++) cin >> w[i];fac[0]=1;for(int i=1;i<MAXNN;i++) fac[i]=1ll*fac[i-1]*i%mod;invfac[MAXNN-1]=Fp(fac[MAXNN-1],mod-2);for(int i=MAXNN-2;i>=0;i--) invfac[i]=1ll*invfac[i+1]*(i+1)%mod;for(int i=0;i<=m;i++) a[i]=1ll*Fp(mod-1,m-i)*invfac[m-i]%mod;for(int i=0;i<=n;i++){if(i>m||s*i>n) break;b[i]=1ll*fac[i]*C(m,i)%mod*fac[n]%mod*Fp(invfac[s],i)%mod*Fp(m-i,n-s*i)%mod*invfac[n-s*i]%mod;}int lim=1,l=0;while(lim<=m+m+2) lim<<=1,l++;for(int i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);NTT(a,lim,1); NTT(b,lim,1);for(int i=0;i<lim;i++) a[i]=1ll*a[i]*b[i]%mod;NTT(a,lim,-1);int ans=0;for(int i=0;i<=m;i++) ans=(ans+1ll*w[i]*a[m+i]%mod*invfac[i]%mod)%mod;cout << ans << endl;return 0;
}

4.拉格朗日插值

由 nnn 个点值可以唯一确定一个 n−1n - 1n−1 次多项式。

f(k)=∑i=1nyi∏j≠ik−xjxi−xjf(k) = \sum_{i = 1}^ny_i\prod_{j \not= i}\frac{k - x_j}{x_i - x_j}f(k)=i=1∑n​yi​j=i∏​xi​−xj​k−xj​​

考虑模意义下的证明:
对于 nnn 个点值而言,有 f(k)≡yi(mod(k−xi))f(k)\equiv y_i (\bmod (k - x_i))f(k)≡yi​(mod(k−xi​)) ,(将 f(x)f(x)f(x) 展开,显然可证),根据 CRT ,有:

f(k)=∑i=1nyi∏j=1n(k−xj)∏j≠i(xi−xj)f(k) = \sum_{i = 1}^n y_i\frac{\prod_{j = 1}^n (k - x_j)}{\prod_{j\not = i}(x_i - x_j)}f(k)=i=1∑n​yi​∏j=i​(xi​−xj​)∏j=1n​(k−xj​)​

整理可得。

模板题 洛谷 P4781
依照式子计算即可。

#include<iostream>
#include<cstdio>
#define MAXN 2005using namespace std;const int mod=998244353;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int n,k,x[MAXN],y[MAXN];int main(){cin >> n >> k;for(int i=1;i<=n;i++){cin >> x[i] >> y[i];}int ans=0;for(int i=1;i<=n;i++){int fz=y[i]%mod,fm=1;for(int j=1;j<=n;j++){if(i^j){fz=1ll*fz*((k-x[j]+mod)%mod)%mod;fm=1ll*fm*((x[i]-x[j]+mod)%mod)%mod;}}ans=(ans+1ll*fz*Fp(fm,mod-2))%mod;}cout << ans << endl;return 0;
}

例题 CF622F The Sum of the k-th Powers

求 ∑i=1nik\sum_{i = 1}^ni^k∑i=1n​ik ,n≤109,k≤106n\leq10^9,k\leq10^6n≤109,k≤106 。

我们不加证明地给出一个非常常见的结论, ∑i=1nik\sum_{i = 1}^ni^k∑i=1n​ik 是一个 k+1k + 1k+1 次的多项式,因此,用 k+2k + 2k+2 个点值就可以确定这个多项式,很显然,如果我们取 [1,k+2][1,k + 2][1,k+2] ,对于求和号里的式子是可以做到预处理后 O(1)O(1)O(1) 求的,于是整体的式子就是 O(nlog⁡n)O(n\log n)O(nlogn) 的,直接输出即可。

#include<iostream>
#include<cstdio>
#define MAXN 1000005using namespace std;int n,k,fac[MAXN],pre[MAXN],suf[MAXN],sum[MAXN];const int mod=1e9+7;int Fp(int x,int tms){int ret=1;while(tms){if(tms&1) ret=1ll*ret*x%mod;x=1ll*x*x%mod; tms>>=1;}return ret;
}int main(){cin >> n >> k;fac[0]=pre[0]=1;for(int i=1;i<=k+2;i++){fac[i]=1ll*fac[i-1]*i%mod;pre[i]=1ll*(n-i+mod)%mod*pre[i-1]%mod;sum[i]=(sum[i-1]+Fp(i,k))%mod;}suf[k+3]=1;for(int i=k+2;i>=0;i--)suf[i]=1ll*(n-i+mod)%mod*suf[i+1]%mod;int ans=0;for(int i=1;i<=k+2;i++){int fz=sum[i],fm=1;fz=fz*1ll*pre[i-1]%mod*suf[i+1]%mod;fm=fm*1ll*fac[i-1]%mod*fac[k+2-i]%mod;if((k+2-i)%2==1) fm=mod-fm;ans=(ans+1ll*fz*Fp(fm,mod-2)%mod)%mod;}cout << ans << endl;return 0;
}

(证明咕了,能补就补)

NOIP数学学习笔记 Sakura_xyz相关推荐

  1. 数学学习笔记--线性代数

    开始复习 AI 算法的基础–数学部分,主要是三方面的内容: 线性代数 概率论 微积分 参考内容如下: <深度学习> https://github.com/scutan90/DeepLear ...

  2. 白话机器学习的数学学习笔记(-)

    机器学习越来越成为未来科技进步的推动,其中的数学理论还是需要学习和补充的,今天购买了<白话机器学习的数学>一书,就把相关学习到的知识做下笔记,供感兴趣的伙伴一起回顾. 一.1950年左右人 ...

  3. 数学学习笔记--概率论

    2. 概率论 2.1 概率分布与随机变量 2.1.1 机器学习为什么要使用概率 事件的概率是衡量该事件发生的可能性的量度.虽然在一次随机试验中某个事件的发生是带有偶然性的,但那些可在相同条件下大量重复 ...

  4. 数学学习笔记-三角函数

    1.圆的一周的弧度数为2π,360°角=2π弧度,1°为π/180弧度 2.如下图,在一个直角三角形中 角A的对边为正对着的那个边a 角A的邻边为另外一条直角边b 角A的斜边为斜边c 其中 正弦sin ...

  5. [数学学习笔记]极限的概念.

    百科上的定义: 极限是微积分中的基础概念,它指的是变量在一定的变化过程中,从总的来说逐渐稳定的这样一种变化趋势以及所趋向的值(极限值).极限的概念最终由柯西和魏尔斯特拉斯等人严格阐述.在现代的数学分析 ...

  6. 数学学习笔记(二)柯西-黎曼方程理解

    理解不一定对,只是一种感悟,想简单记录一下. 柯西-黎曼方程是复变函数在一点可微的必要条件,证明不难.因为可微,所以就列出线性主部表出的一个式子,实部对实部,虚部对虚部,可以求得 这个方程式很简单,随 ...

  7. [数学学习笔记]无穷小与无穷大

    无穷小: 定义:极限为0的变量成为无穷小量,简称无穷小.常用希腊字母表示. 无穷小是一个特殊的变量: 无穷小不可以和很小的量混为一谈,无穷小量不是指量的大小,而是指量的变化趋势(以零为极限): 称一个 ...

  8. Unity 中的 3D 数学学习笔记——认识坐标系及坐标系之间的转换

    一 :3d空间坐标系  x,y,z 轴 z轴方向确定有两种方式 左手坐标系和右手坐标系 左手坐标系:伸开左手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向. 右手坐标系:伸开右 ...

  9. [数学学习笔记]导数的运算

    基本初等函数 初等函数是由基本初等函数经过有限次的四则运算和复合运算所得到的函数.基本初等函数和初等函数在其定义区间内均为连续函数. 高等数学将基本初等函数归为五类:幂函数.指数函数.对数函数.三角函 ...

  10. matlab中x从0到5不含0,关于MATLAB的数学建模算法学习笔记

    关于MATLAB的数学建模算法学习笔记 目录 线性规划中应用: (3) 非线性规划: (3) 指派问题;投资问题:(0-1问题) (3) 1)应用fmincon命令语句 (3) 2)应用指令函数:bi ...

最新文章

  1. 电子邮件的故事:令人吃惊的预测
  2. java中synchronized介绍和用法
  3. 第29月第21天 ios android curl
  4. HDU 1115 Lifting the Stone(求多边形重心)
  5. System.InvalidOperationException : 不应有 Response xmlns=''。
  6. java通过commons-fileupload实现多张图片的上传(jsp页面)
  7. mysql 磁盘组_有效管理 ASM 磁盘组空间
  8. 《Nature》颠覆性发现!第四种热传递方式找到了
  9. #25 centos7(RHEL)系列操作系统的启动流程、systemd的特性、与命令systemctl的使用...
  10. android+usb转串口+唯一id,Android平台3G模块驱动移植-USB转串口
  11. Android开发工具之DDMS
  12. 《Frustum PointNets for 3D Object Detection from RGB-D Data》论文及代码学习(二)——代码部分
  13. “计算机组成原理”视频资料(加上全集链接啦)
  14. Spark性能优化之-资源调优
  15. 什么是 WPS(Wi-Fi Protected Setup)
  16. $(this)与this的区别
  17. 【C++探索之旅】第一部分第二课:C++编程的必要软件
  18. python自动化生成请假条
  19. 谷歌应用商店现木马程序、百万WiFi路由器面临漏洞风险|12月6日全球网络安全热点
  20. python开发的炸金花小游戏来啦,从此不再无聊~

热门文章

  1. linux oel7没有网络,sudo su命令不在OEL 7中工作(sudo su command not working in OEL 7)
  2. 英特尔芯片组系列 服务器,英特尔主板现在有几种架构,分别都是什么。都是对应什么系列CPU安装最好。说的越详细越好...
  3. [转] 关于浏览器假死的原因分析和代码优化
  4. 热核特征(heat kernel signature,HKS)简单解释(附可运行代码)
  5. ip地址是计算机设备在网络上的地址,如何查看主机ip 如何查看与自己电脑相连设备的IP地址...
  6. 大数据预测房价湖北暂未实施
  7. 张学友1/2世纪演唱会巡演日程、曲目及新闻汇总
  8. matlab中正弦信号的功率计算,范数norm
  9. Linux tc QOS 详解
  10. 一 . css系列之html需知及ps的基础操作