当前位置: 首页 > news >正文

二项式反演 系列 题解

有时候做一些计数题,会遇到“恰好满足……”类似的条件,往往无法正面击破。但是有可能我们掌握的现有的排列组合 trick 们,可以解决“至少……满足……”的条件,即钦定某些满足……,其它不管。而二项式反演这个既定事实可以实现二者方案数的转化。

二项式反演

我们设 f i f_i fi 表示钦定 i i i 个元素满足某些条件的方案数(其它元素不一定满足), g i g_i gi 表示恰好 i i i 个元素满足某些条件的方案数。那么有既定的关系。

形式一

f n = ∑ i = n m ( i n ) g i ⇔ g n = ∑ i = n m ( − 1 ) i − n ( i n ) f i f_n=\sum_{i=n}^m\binom{i}{n}g_i\Leftrightarrow g_n=\sum_{i=n}^m(-1)^{i-n}\binom{i}{n}f_i fn=i=nm(ni)gign=i=nm(1)in(ni)fi

形式二

f n = ∑ i = 0 n ( n i ) g i ⇔ g n = ∑ i = 0 n ( − 1 ) n − i ( n i ) f i f_n=\sum_{i=0}^n\binom{n}{i}g_i\Leftrightarrow g_n=\sum_{i=0}^n(-1)^{n-i}\binom{n}{i}f_i fn=i=0n(in)gign=i=0n(1)ni(in)fi

证明略,可以参考 OI-WIKI。

实际做题的时候我们发现二者的使用场景和效果略有不同。不过其它的博客似乎并没有很详细的说明,其实可以略微讨论一下。

应用场景区分

形式一适用场景

  • 问题类型:从“至少满足 k k k 个条件”到“恰好满足 k k k 个条件”的转换。
  • 典型问题
    1. 错位排列计数;
    2. 动态规划中“包含冗余状态”的精确计数优化。
  • 已知至少选k个元素的总情况 f ( k ) f(k) f(k),反推恰好选i个元素的情况 g ( i ) g(i) g(i)

形式二适用场景

  • 问题类型:从“全集并集”到“单个集合”的反推。
  • 典型问题
    1. 容斥原理中的交并集转换(如求多个集合的并集大小);
    2. 严格满足所有约束的情况计数。
  • 已知多个集合的并集大小 f ( n ) f(n) f(n),反推单个集合的交集大小 g ( n ) g(n) g(n)

组合意义对比

方向形式一形式二
核心意义分层消除冗余(从高阶到低阶)整体符号反转去重(整体到部分)
组合数作用向下投影: ( i k ) \displaystyle\binom{i}{k} (ki)同层展开: ( n i ) \displaystyle\binom{n}{i} (in)
符号项意义消除高阶项的叠加贡献 ( − 1 ) i − k (-1)^{i-k} (1)ik消除重复计数( ( − 1 ) n − i (-1)^{n-i} (1)ni

因此在二项式反演的最广泛的应用场景,“钦定”和“恰好”的转换中,最常用形式一。 f f f 为钦定, g g g 为恰好,那么:
f n = ∑ i = n m ( n i ) g i ⇔ g n = ∑ i = n m ( − 1 ) i − n ( n i ) f i f_n=\sum_{i=n}^m\binom{n}{i}g_i\Leftrightarrow g_n=\sum_{i=n}^m(-1)^{i-n}\binom{n}{i}f_i fn=i=nm(in)gign=i=nm(1)in(in)fi

1.洛谷 P5505 分特产

题意

JYY 带回了 m m m 种特产,每种特产有 a i a_i ai 个,要分给实验室的同学们。他想知道,把这些特产分给 n n n 个同学,一共有多少种不同的分法?当然,JYY 不希望任何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。

分法方案数对 1 0 9 + 7 10^9+7 109+7 取模。

1 ≤ n , m ≤ 1000 1\le n,m\le 1000 1n,m1000

思路

先正难则反,考虑转化问题为,恰好 0 0 0 个同学没有分到产品,即 g 0 g_0 g0。那么我们钦定 f i f_i fi 表示钦定 i i i 个同学没有分到特产。

我们钦定 i i i 个人没有得到特产 ( n i ) \displaystyle\binom{n}{i} (in),对于每种特产 a j a_j aj,我们可以随意分给剩下的 n − i n-i ni 个人,不管有或没有特产。

这里我们使用“插板法”:我们把 a j a_j aj 分成 n − i n-i ni 部分,但是可以留空。我们插“多余板” n − i n-i ni 个,转化为把 a j + ( n − i ) a_j+(n-i) aj+(ni) 分成 n − i n-i ni 部分,不可以留空,这个问题就好了: ( a j + ( n − i ) − 1 ( n − i ) − 1 ) \displaystyle\binom{a_j+(n-i)-1}{(n-i)-1} ((ni)1aj+(ni)1)

那么:
f i = ( n i ) ( a j + ( n − i ) − 1 ( n − i ) − 1 ) f_i=\binom{n}{i}\binom{a_j+(n-i)-1}{(n-i)-1} fi=(in)((ni)1aj+(ni)1)

我们用形式一转成 g 0 g_0 g0 即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll N=3003,mod=1e9+7;
ll n,m,a[N];
ll C[N][N];
ll f[N];
void init()
{for(int i=1;i<N;i++)C[i][0]=C[i][i]=1;for(int i=1;i<N;i++)for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
int main()
{init();scanf("%lld%lld",&n,&m);for(int i=1;i<=m;i++)scanf("%lld",&a[i]);for(int i=0;i<=n;i++){f[i]=C[n][i];for(int j=1;j<=m;j++)f[i]=f[i]*C[a[j]+n-i-1][n-i-1]%mod;}ll ans=0;for(int i=0;i<=n;i++){ll op=(i&1?-1:1);ans=(ans+op*f[i]+mod)%mod;}printf("%lld",ans);return 0;
}

2.洛谷 P10596/BZOJ2839 集合计数

思路

一个有 n n n 个元素的集合有 2 n 2^n 2n 个不同子集(包含空集),现在要在这 2 n 2^n 2n 个集合中取出若干集合(至少一个),使得它们的交集的元素个数为 m m m,求取法的方案数,答案模 1 0 9 + 7 10^9+7 109+7

1 ≤ n ≤ 1000000 1\leq n\leq 1000000 1n1000000 0 ≤ m ≤ n 0\leq m\leq n 0mn

思路

我们考虑枚举交集大小。钦定 i i i 个元素作为交集,剩下的 n − i n-i ni 个随便排,不管有没有在交集里面。那么剩下的 n − i n-i ni 个能组成 2 n − i 2^{n-i} 2ni 个集合,这 2 n − i 2^{n-i} 2ni 个集合各自可以选可以不选,但是不能全部不选(不然就算上空集了),所以有 2 2 n − i − 1 2^{2^{n-i}}-1 22ni1 种选法。

f i f_i fi 表示钦定 i i i 个元素作为交集(其它概念同上)的方案数, g i g_i gi 表示恰有 i i i 个元素作为交集的方案数,那么有:
f i = ( n i ) ( 2 2 n − i − 1 ) f_i=\binom{n}{i}\left(2^{2^{n-i}}-1\right) fi=(in)(22ni1)

然后用形式一转成 g m g_m gm 即可。

有几点要注意的,首先那个二的二的次幂比较恐怖,快速幂可能干到 2 1 0 9 + 6 2^{10^9+6} 2109+6,还是预处理稳妥;然后因为 k ≤ 0 k\le 0 k0,所以钦定的时候记得计算交集为空集的方案。具体细节见代码。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e6+9,mod=1e9+7;
ll n,m;
ll f[N];
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
ll fac[N],inv[N],pp2[N];
void init()
{pp2[0]=2;for(int i=1;i<=n;i++)pp2[i]=pp2[i-1]*pp2[i-1]%mod;fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;inv[N-1]=qpow(fac[N-1],mod-2);for(int i=N-2;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m)
{if(n<m)return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{scanf("%lld%lld",&n,&m);init();for(int i=0;i<=n;i++)f[i]=C(n,i)*(pp2[n-i]-1)%mod;ll gm=0;for(int i=m;i<=n;i++){ll op=((i-m)&1?-1:1);gm=(gm+op*C(i,m)%mod*f[i]%mod+mod)%mod;}printf("%lld",gm);return 0;
}

3.洛谷 P4859 已经没有什么好害怕的了

题意

Charlotte 的结界中有两种具有能量的元素,一种是“糖果”,另一种是“药片”,各有 n n n 个。在 Charlotte 发动进攻前,“糖果”和“药片”会两两配对,若恰好糖果比药片能量大的组数比“药片”比“糖果”能量大的组数多 k k k 组,则在这种局面下,Charlotte 的攻击会丟失,从而 Mami 仍有消灭 Charlotte 的可能。

你必须根据 Homura 告诉你的“糖果”和“药片”的能量的信息迅速告诉 Homura 这种情况的个数。

保证“糖果”和“药片”的能量参数各不相同。答案对 1 0 9 + 9 10^9+9 109+9 取模。

1 ≤ n ≤ 2000 1 \le n \le 2000 1n2000 0 ≤ k ≤ n 0 \le k \le n 0kn

思路

看到 n n n 支持 Θ ( n 2 ) \Theta(n^2) Θ(n2),而且属于两个数组进行匹配的问题,dp 时可以设置二维状态。

我们看到题目,根据题目要求动用小奥知识,“恰好糖果比药片能量大的组数”应为 m = n + k 2 m=\dfrac{n+k}{2} m=2n+k

那么我们考虑枚举每个 a i a_i ai,每次计算可以添加多少 b j b_j bj,从而计算出,当前配对有前 i i i a a a 数组元素,有 j j j b b b 数组元素小于 i i i a a a 数组元素的方案数,设为 F i , j F_{i,j} Fi,j

考虑向 F i , j F_{i,j} Fi,j 转移,如果添加一个 a a a F i , j ← F i − 1 , j F_{i,j}\leftarrow F_{i-1,j} Fi,jFi1,j;如果从 j − 1 j-1 j1 个转移到 j j j 个,那么我们要找比 a i a_i ai 小的在 b b b 数组中还有多少个没有被选。

这样算配对数,其实和 a i a_i ai 的加入顺序无关,是个组合。因此我们对 a , b a,b a,b 数组从小到大排序,那么当前 F i , j F_{i,j} Fi,j 代表的状态合法的话,总是满足 a i > b 1 ∼ j a_i>b_{1\sim j} ai>b1j

刚刚说我们要找“比 a i a_i ai 小的在 b b b 数组中还有多少个没有被选”,因为此时 a , b a,b a,b 数组均有序,所以我们可以用双指针计算比 a i a_i ai 小的数在 b b b 数组中总共有 l e s i les_i lesi 个。因为在合法状态 F i , j − 1 F_{i,j-1} Fi,j1 中,比 a i a_i ai 小的有 j − 1 j-1 j1 个,那么还有 l e s i − ( j − 1 ) les_i-(j-1) lesi(j1) 个比 a i a_i ai 小的没选。那么:
F i , j ← F i , j − 1 × [ l e s i − ( j − 1 ) ] F_{i,j}\leftarrow F_{i,j-1}\times[les_i-(j-1)] Fi,jFi,j1×[lesi(j1)]

初始化 F 0 , 0 = 1 F_{0,0}=1 F0,0=1

sort(a+1,a+n+1);
sort(b+1,b+n+1);
ll pos=1;
for(int i=1;i<=n;i++)
{while(pos<=n&&b[pos]<a[i])pos++;les[i]=pos-1;
}
F[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
F[i][j]=(F[i-1][j]+F[i-1][j-1]*(les[i]-(j-1)+mod)%mod)%mod;

我们设 f i f_i fi 表示钦定了 i i i 个要小于配对中的 a a a 数组元素,剩下的 n − i n-i ni 个随便大于小于; g i g_i gi 表示恰好有 i i i 小于配对中的 a a a 数组元素。那么就是钦定的 F n , i F_{n,i} Fn,i,后面乱排 ( n − i ) ! (n-i)! (ni)!,所以:
f i = F n , i × ( n − i ) ! f_i=F_{n,i}\times (n-i)! fi=Fn,i×(ni)!

用形式一转回 g m g_m gm 即可, m = n + k 2 m=\dfrac{n+k}{2} m=2n+k

注意模数。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2002,mod=1e9+9;
ll n,k,m,a[N],b[N];
ll les[N],F[N][N],f[N],gm;
//F(i,j):当前匹配,a的前i个数当中,有j个b中数小于a的方案数 
ll C[N][N],fac[N];
void init()
{for(int i=0;i<N;i++)C[i][0]=C[i][i]=1;for(int i=1;i<N;i++)for(int j=1;j<i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;
}
int main()
{init();scanf("%lld%lld",&n,&k);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<=n;i++)scanf("%lld",&b[i]);sort(a+1,a+n+1);sort(b+1,b+n+1);if((n+k)&1){puts("0");return 0; }m=(n+k)/2;ll pos=1;for(int i=1;i<=n;i++){while(pos<=n&&b[pos]<a[i])pos++;les[i]=pos-1;}F[0][0]=1;for(int i=1;i<=n;i++)for(int j=0;j<=i;j++)F[i][j]=(F[i-1][j]+F[i-1][j-1]*(les[i]-(j-1)+mod)%mod)%mod;for(int i=1;i<=n;i++)f[i]=F[n][i]*fac[n-i]%mod;//剩下钦定了i个要小于a中的数,剩下n-i个随便排for(int i=m;i<=n;i++){ll op=((i-m)&1?-1:1);gm=(gm+op*f[i]%mod*C[i][m]%mod+mod)%mod;//用形式2还原 }printf("%lld",gm);return 0;
}

4.洛谷 P6478 游戏

题意

小 A 和小 B 正在玩一个游戏:有一棵包含 n = 2 m n=2m n=2m 个点的有根树,它的根是 1 1 1 号点,初始时两人各拥有 m m m 个点。游戏的每个回合两人都需要选出一个自己拥有且之前未被选过的点,若对手的点在自己的点的子树内,则该回合自己获胜;若自己的点在对方的点的子树内,该回合自己失败;其他情况视为平局。游戏共进行 m m m 回合。

作为旁观者的你只想知道,在他们随机选点的情况下,第一次非平局回合出现时的回合数的期望值。

为了计算这个期望,你决定对于 k = 0 , 1 , 2 , ⋯ , m k=0,1,2,\cdots,m k=0,1,2,,m,计算出非平局回合数为 k k k 的情况数,即在 k k k 局后平局了。两种情况不同当且仅当存在一个小 A 拥有的点 x x x,小 B 在 x x x 被小 A 选择的那个回合所选择的点不同。

由于情况总数可能很大,你只需要输出答案对 998244353 998244353 998244353 取模后的结果。

n ≤ 5000 n\le 5000 n5000

思路

我们先钦定 i i i 局为非平局,后面的是不是平局均可。设 f i f_i fi 表示至少 i i i 局非平局的方案数, g i g_i gi 表示恰好 i i i 局是非平局然后就平局了的方案数。

这题还是个树形 dp,我们需要知道树上会出现多少非平局。我们不妨设 F u , x F_{u,x} Fu,x 表示 u u u 子树内出现了多少非平局,非平局出现的条件是存在一对父子颜色不同。

对于不包括 v v v 子树的子树 u u u 和子树 v v v,其中的分别有 x x x y y y 对非平局点对,那么对整个 u u u 子树贡献到 x + y x+y x+y 个点对的话,根据乘法原理,其方案数有 F u , x + y = F u , x × F v , y F_{u,x+y}=F_{u,x}\times F_{v,y} Fu,x+y=Fu,x×Fv,y,不过我们发现如果直接更新 F u , x + y F_{u,x+y} Fu,x+y 会和式子中的 F u , x F_{u,x} Fu,x 有冲突,因此使用辅助数组记录:

for(int x=0;x<=siz[u]+siz[v];x++)
tem[x]=0;
for(int x=0;x<=siz[u];x++)
for(int y=0;y<=siz[v];y++)
tem[x+y]=(tem[x+y]+F[u][x]*F[v][y]%mod)%mod;
for(int x=0;x<=siz[u]+siz[v];x++)
F[u][x]=tem[x];

除了合并其它子树的方案数,我们还可以新加入点对。对于完全体的 u u u 子树,当前已经产生了 x x x 对非平局点对(即状态 F u , x F_{u,x} Fu,x),我们考虑新加 u u u 和其它其它异色点的非平局关系,从 F u , x − 1 F_{u,x-1} Fu,x1 转移过来,只需要知道 u u u 子树内还有多少和 u u u 异色的点,且这些点没有和其它异色点产生非平局关系

我们记 c n t 1 u cnt1_u cnt1u 表示 u u u 子树内有多少颜色为 1 1 1 的节点,那么颜色为 0 0 0 c n t 0 u = s i z u − c n t 1 u cnt0_u=siz_u-cnt1_u cnt0u=sizucnt1u。我们不难发现,子树内 x − 1 x-1 x1 个非平局点对中,肯定有 x − 1 x-1 x1 个和 u u u 同色的、也有 x − 1 x-1 x1 个和 u u u 异色的,因此:

  • c o l u = 1 col_u=1 colu=1,那么子树内还有 c n t 0 − ( x − 1 ) cnt0-(x-1) cnt0(x1) 个异色点可以选;
  • c o l u = 0 col_u=0 colu=0,那么子树内还有 c n t 1 − ( x − 1 ) cnt1-(x-1) cnt1(x1) 个异色点可以选。

因此:
{ F u , x ← F u , x − 1 × [ c n t 0 − ( x − 1 ) ] , c o l u = 1 F u , x ← F u , x − 1 × [ c n t 1 − ( x − 1 ) ] , c o l u = 0 \left\{\begin{matrix} F_{u,x}\leftarrow F_{u,x-1}\times[cnt0-(x-1)],col_u=1\\ F_{u,x}\leftarrow F_{u,x-1}\times[cnt1-(x-1)],col_u=0 \end{matrix}\right. {Fu,xFu,x1×[cnt0(x1)],colu=1Fu,xFu,x1×[cnt1(x1)],colu=0

树形 dp 就告一段落。我们回到“钦定恰好”的状态: F 1 , i F_{1,i} F1,i 表示,在整棵树内有 i i i 对非平局点对,因为是钦定,剩下 m − i m-i mi 对( m − i m-i mi 1 1 1 色和 m − i m-i mi 0 0 0 色)随便排,那么:
f i = F 1 , i × ( m − i ) ! f_i=F_{1,i}\times (m-i)! fi=F1,i×(mi)!

用形式一还原出 g 0 ∼ m g_{0\sim m} g0m 即可, a n s = ∑ i = 0 m g i ans=\displaystyle\sum_{i=0}^mg_i ans=i=0mgi

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5002,mod=998244353;
char s[N];
ll n,m;
bool col[N];
ll idx,head[N];
struct edge
{ll to,next;
}e[N<<1];
void addedge(ll u,ll v)
{idx++;e[idx].to=v;e[idx].next=head[u];head[u]=idx;
}
ll C[N][N],fac[N];
void init()
{for(int i=0;i<N;i++)C[i][0]=C[i][i]=1;for(int i=1;i<N;i++)for(int j=1;j<i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;
}
ll siz[N],cnt1[N],F[N][N],tem[N];
ll f[N],g[N];
void dfs(ll u,ll fa)
{siz[u]=1;cnt1[u]=col[u];F[u][0]=1;for(int i=head[u];i;i=e[i].next){ll v=e[i].to;if(v==fa)continue;dfs(v,u);for(int x=0;x<=siz[u]+siz[v];x++)tem[x]=0;for(int x=0;x<=siz[u];x++)for(int y=0;y<=siz[v];y++)tem[x+y]=(tem[x+y]+F[u][x]*F[v][y]%mod)%mod;for(int x=0;x<=siz[u]+siz[v];x++)F[u][x]=tem[x];siz[u]+=siz[v];cnt1[u]+=cnt1[v];}ll n1=cnt1[u],n0=siz[u]-cnt1[u];for(int x=min(n1,n0);x>=1;x--){if(col[u])F[u][x]=(F[u][x]+F[u][x-1]*(n0-(x-1))%mod)%mod;else F[u][x]=(F[u][x]+F[u][x-1]*(n1-(x-1))%mod)%mod;}
}
int main()
{init();scanf("%lld%s",&n,s+1);for(int i=1;i<=n;i++)col[i]=(ll)s[i]-'0';m=n/2;for(int i=1;i<n;i++){ll u,v;scanf("%lld%lld",&u,&v);addedge(u,v);addedge(v,u);}dfs(1,0);for(int i=0;i<=m;i++)f[i]=F[1][i]*fac[m-i]%mod;ll ans=0;for(int i=0;i<=m;i++){for(int j=i;j<=m;j++){ll op=((j-i)&1?-1:1);g[i]=(g[i]+op*f[j]%mod*C[j][i]+mod)%mod;}printf("%lld\n",g[i]);}return 0;
}

5.洛谷 P6076 JSOI2015 染色问题

题意

萌萌家有一个棋盘,这个棋盘是一个 n × m n \times m n×m 的矩形,分成 n n n m m m 列共 n × m n \times m n×m 个小方格。
现在萌萌和南南有 c c c 种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定:

  1. 棋盘的每一个小方格既可以染色(染成 c c c 种颜色中的一种),也可以不染色。
  2. 棋盘的每一行至少有一个小方格被染色。
  3. 棋盘的每一列至少有一个小方格被染色。
  4. 每种颜色都在棋盘上出现至少一次。

以下是一些将 3 × 3 3 \times 3 3×3 棋盘染成 c = 3 c=3 c=3 种颜色(红、黄、蓝)的例子(下图已更新):

请你求出满足要求的不同的染色方案总数。只要存在一个位置的颜色不同,即认为两个染色方案是不同的。

答案对 1 0 9 + 7 10^9+7 109+7 取模的值。

1 ≤ n , m , c ≤ 400 1 \le n,m,c \le 400 1n,m,c400

思路

这里讲二项式反演的思路,纯容斥原理的做法以后再写。

我们看到非常多的“至少一个”,其实和 1. 1. 1. 思考方式差不多,我们仍然正难则反,看行列没有染和颜色没有用。

f i , j , t f_{i,j,t} fi,j,t 表示至少 i i i j j j 列没染、至少 t t t 色没用的方案数, g i , j , t g_{i,j,t} gi,j,t 表示恰好有 i i i j j j 列没染、恰好 t t t 色没用的方案数,最终答案就是 g 0 , 0 , 0 g_{0,0,0} g0,0,0

对于 f i , j , t f_{i,j,t} fi,j,t 先选定那些行列没染和那些颜色没用,然后对于剩下的 ( n − i ) × ( m − j ) (n-i)\times(m-j) (ni)×(mj) 个格子,可以填没有被选定的 c − t c-t ct 色和不填,那么:
f i , j , t = ( n i ) ( m j ) ( c t ) ( c − t + 1 ) ( n − i ) ( m − j ) f_{i,j,t}=\binom{n}{i}\binom{m}{j}\binom{c}{t}(c-t+1)^{(n-i)(m-j)} fi,j,t=(in)(jm)(tc)(ct+1)(ni)(mj)

我们发现如果要转回 g g g,这是一个高维二项式反演,但是其实容易证明:
f x , y , z = ∑ i = x n ∑ j = y m ∑ k = z c ( i x ) ( j y ) ( k z ) g i , j , k ⇔ g x , y , z = ∑ i = x n ∑ j = y m ∑ k = z c ( i x ) ( j y ) ( k z ) ( − 1 ) i + j + k − x − y − z f i , j , k \begin{matrix} f_{x,y,z}=\displaystyle\sum_{i=x}^n\sum_{j=y}^m\sum_{k=z}^c\binom{i}{x}\binom{j}{y}\binom{k}{z}g_{i,j,k}\\ \Leftrightarrow g_{x,y,z}=\displaystyle\sum_{i=x}^n\sum_{j=y}^m\sum_{k=z}^c\binom{i}{x}\binom{j}{y}\binom{k}{z}(-1)^{i+j+k-x-y-z}f_{i,j,k} \end{matrix} fx,y,z=i=xnj=ymk=zc(xi)(yj)(zk)gi,j,kgx,y,z=i=xnj=ymk=zc(xi)(yj)(zk)(1)i+j+kxyzfi,j,k

那么 g 0 , 0 , 0 = ∑ i = 0 n ∑ j = 0 m ∑ k = 0 c ( − 1 ) i + j + k f i , j , k = ∑ i = 0 n ∑ j = 0 m ∑ k = 0 c ( − 1 ) i + j + k ( n i ) ( m j ) ( c t ) ( c − t + 1 ) ( n − i ) ( m − j ) g_{0,0,0}=\displaystyle\sum_{i=0}^n\sum_{j=0}^m\sum_{k=0}^c (-1)^{i+j+k}f_{i,j,k}=\displaystyle\sum_{i=0}^n\sum_{j=0}^m\sum_{k=0}^c (-1)^{i+j+k}\binom{n}{i}\binom{m}{j}\binom{c}{t}(c-t+1)^{(n-i)(m-j)} g0,0,0=i=0nj=0mk=0c(1)i+j+kfi,j,k=i=0nj=0mk=0c(1)i+j+k(in)(jm)(tc)(ct+1)(ni)(mj)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=402,mod=1e9+7;
ll n,m,c;
ll g000;
ll C[N][N];
void init()
{for(int i=0;i<N;i++)C[i][0]=C[i][i]=1;for(int i=1;i<N;i++)for(int j=1;j<i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
int main()
{init();scanf("%lld%lld%lld",&n,&m,&c);for(int i=0;i<=n;i++){for(int j=0;j<=m;j++){for(int t=0;t<=c;t++){ll op=((i+j+t)&1?-1:1);g000=(g000+op*C[n][i]*C[m][j]%mod*C[c][t]%mod*qpow(c-t+1,(n-i)*(m-j))%mod+mod)%mod;}}}printf("%lld",g000);return 0;
}

相关文章:

  • 【蓝牙协议栈】【BR/EDR】【AVCTP】精讲音视频控制传输协议
  • BUUCTF 大流量分析(一) 1
  • AUTOSAR图解==>AUTOSAR_SRS_CryptoStack
  • 从0开始学习大模型--Day01--大模型是什么
  • Linux 常用指令详解
  • tensorflow 调试
  • Lombok 是什么?
  • 014枚举之指针尺取——算法备赛
  • 【Linux网络#17】TCP全连接队列与tcpdump抓包
  • LeetCode 热题 100 78. 子集
  • 洛谷 P9007 [入门赛 #9] 最澄澈的空与海 (Hard Version)
  • N-Gram 模型
  • 基于Vue3开发:打造高性能个人博客与在线投票平台
  • Java---Object和内部类
  • 协程补充---viewModelScope 相关知识点
  • 蓝桥杯 19. 植树
  • 事务隔离(MySQL)
  • 5.4 - 5.5Web基础+c语言拓展功能函数
  • sqli-labs靶场11-17关(POST型)
  • 深度解析:从 GPT-4o“谄媚”到 Deepseek“物理腔”,透视大模型行为模式的底层逻辑与挑战
  • 4月份全球制造业PMI继续下降,经济下行压力有所加大
  • 北美票房|“雷霆”开画票房比“美队4”低,但各方都能接受
  • 铁路上海站迎五一返程客流最高峰,今日预计到达75.9万人次
  • 最长3个月免费住宿,南昌人才驿站(洪漂驿站)申请指南发布
  • 当Z世代与传统戏曲在春日校园相遇
  • 巴菲特股东大会十大金句:未来五年内可能有投资机会,快乐的人活得更久