介绍
对于一个集合 U = { a 1 , a 2 , a 3 , . . . , a n } U=\{a_1,a_2,a_3,...,a_n\} U={a1,a2,a3,...,an},我想要知道其中的 max \max max,但是很不好求,那么就可以通过Min-Max容斥转化为求出它所有子集中的 min \min min。
正题
一切的魔术来源于这个简单的式子:
max
{
U
}
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
+
1
min
{
S
}
\max\{U\}=\sum_{S\subseteq U} (-1)^{|S|+1} \min\{S\}
max{U}=S⊆U∑(−1)∣S∣+1min{S}
( min \min min 转 max \max max 就把上面的 min \min min 和 max \max max 换过来就好了。)
简单易懂的证明:
对于第 k k k 大值,要使它成为 S S S 中的 min \min min,那么剩下的元素只能在比他大的 k − 1 k-1 k−1 个里面选。假如选出了 i i i 个,当 i i i 为奇数时容斥系数为 1 1 1( ( − 1 ) ∣ S ∣ m o d 2 = ( i + 1 ) m o d 2 = 0 = 1 (-1)^{|S|\bmod 2=(i+1)\bmod 2=0}=1 (−1)∣S∣mod2=(i+1)mod2=0=1),当 i i i 为偶数时容斥系数为 − 1 -1 −1。
众所周知的引理: 从 n n n 个元素里选出偶数个数的方案数 减 从 n n n 个元素里选出奇数个数的方案数 等于 [ n = 0 ] [n=0] [n=0]。
证明: 上面的东西描述为式子就是: ∑ i = 0 n ( − 1 ) i ( n i ) \sum_{i=0}^n (-1)^i \binom n i ∑i=0n(−1)i(in)。这个东西显然可以套二项式定理得到 ( 1 − 1 ) n = [ n = 0 ] (1-1)^n=[n=0] (1−1)n=[n=0]。
所以,当 k > 1 k>1 k>1 时,它成为 S S S 中 min \min min 的方案数乘以容斥系数就是 0 0 0,对答案没有贡献;当 k = 1 k=1 k=1 时,贡献恰好为 1 1 1。 □ \square □
证明2: 事实上存在更简单的证法,众所周知容斥的一个经典形式是这样的:
∣
⋃
i
∈
S
A
i
∣
=
∑
T
∈
S
(
−
1
)
∣
T
∣
−
1
∣
⋂
j
∈
T
A
j
∣
|\bigcup_{i\in S}A_i|=\sum_{T\in S}(-1)^{|T|-1} |\bigcap_{j\in T} A_j|
∣i∈S⋃Ai∣=T∈S∑(−1)∣T∣−1∣j∈T⋂Aj∣
假如我们令一个元素 i i i 代表一个集合 { 1 , 2 , ⋯ , i } \{1,2,\cdots,i\} {1,2,⋯,i},那么就会发现Min-Max容斥和这个式子完全等价。 □ \square □
然后这条式子在期望下也是满足的,因为所有情况下都满足,求和后再除以情况总数等式依然成立,即:
E
(
max
{
U
}
)
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
+
1
E
(
min
{
S
}
)
E(\max\{U\})=\sum_{S\subseteq U} (-1)^{|S|+1} E(\min\{S\})
E(max{U})=S⊆U∑(−1)∣S∣+1E(min{S})
例题1
令 U = { a i ∣ i ∈ [ 1 , n ] } U=\{a_i|i\in[1,n]\} U={ai∣i∈[1,n]}, a i a_i ai 表示第 i i i 张卡片收集到的时间,那么答案就是 E ( max { U } ) E(\max\{U\}) E(max{U})。
利用Min-Max容斥,问题变成求 E ( min { S } ) ( S ⊆ U ) E(\min\{S\})(S\subseteq U) E(min{S})(S⊆U)。
令 g S = ∑ i ∈ S a i g_S=\sum_{i\in S} a_i gS=∑i∈Sai,显然有 E ( min { S } ) = 1 g S E(\min\{S\})=\dfrac 1 {g_S} E(min{S})=gS1。
或者说,你如果觉得这玩意不显然,那么你可以看看这个推式子:枚举
min
{
S
}
=
k
\min\{S\}=k
min{S}=k,那么前
k
−
1
k-1
k−1 次不能收集到
S
S
S 内的卡,第
k
k
k 次必须收集到
S
S
S 内的卡,那么有:
E
(
min
{
S
}
)
=
∑
k
=
1
∞
k
×
(
1
−
g
S
)
k
−
1
×
g
S
E(\min\{S\})=\sum_{k=1}^{\infty} k\times (1-g_S)^{k-1}\times g_S
E(min{S})=k=1∑∞k×(1−gS)k−1×gS
生成函数使用熟练的选手知道,当
x
∈
(
0
,
1
)
x\in(0,1)
x∈(0,1) 时,
∑
i
=
0
∞
(
i
+
1
)
x
i
=
1
(
1
−
x
)
2
\sum_{i=0}^{\infty} (i+1)x^i=\dfrac 1 {(1-x)^2}
∑i=0∞(i+1)xi=(1−x)21,代入得:
E
(
min
{
S
}
)
=
g
S
(
1
−
(
1
−
g
S
)
)
2
=
1
g
S
E(\min\{S\})=\frac {g_S} {(1-(1-g_S))^2}=\frac1 {g_S}
E(min{S})=(1−(1−gS))2gS=gS1
那么就做完了,代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,cnt[1<<20],sz[1<<20];
double a[20],g[1<<20],ans;
int main()
{
for(int i=0;i<20;i++)cnt[1<<i]=i;
for(int i=1;i<(1<<20);i++)sz[i]=sz[i>>1]+(i&1);
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)scanf("%lf",&a[i]);
for(int S=1;S<(1<<n);S++)
g[S]=g[S-(S&-S)]+a[cnt[S&-S]];
ans=0;for(int S=1;S<(1<<n);S++){
if(sz[S]&1)ans+=1/g[S];
else ans-=1/g[S];
}
printf("%.5lf\n",ans);
}
}
例题2
跟例题1其实是很像的,就是每次得到一张卡和得到多张卡的区别而已。
照例设 U = { a i ∣ i ∈ [ 1 , n ] } U=\{a_i|{i\in [1,n]}\} U={ai∣i∈[1,n]}, a i a_i ai 为第 i i i 为变成 1 1 1 的时间,答案为 E ( max { U } ) E(\max\{U\}) E(max{U}),通过Min-Max容斥转化成求 E ( min { S } ) E(\min\{S\}) E(min{S})。
令 g S = ∑ P ⊆ S a P g_S=\sum_{P\subseteq S}a_P gS=∑P⊆SaP, a P a_P aP 是题目中给的概率, g S g_S gS 就是抽到 S S S 的子集的概率。(注意,可能抽到空集)
令
min
{
S
}
=
k
\min\{S\}=k
min{S}=k,那么前
k
−
1
k-1
k−1 次不能抽到
S
S
S 的子集,第
k
k
k 次必定抽到
S
S
S 的子集,即:
E
(
min
{
S
}
)
=
∑
k
=
1
∞
k
×
g
U
⊕
S
k
−
1
×
(
1
−
g
U
⊕
S
)
E(\min\{S\})=\sum_{k=1}^{\infty} k\times g_{U\oplus S}^{k-1}\times (1-g_{U\oplus S})
E(min{S})=k=1∑∞k×gU⊕Sk−1×(1−gU⊕S)
这个和例题1中的式子是一样的……等于 1 1 − g U ⊕ S \dfrac 1 {1-g_{U\oplus S}} 1−gU⊕S1。
那么就做完了,代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
double a[1<<20],ans=0;
int cnt[1<<20];
int main()
{
scanf("%d",&n);const int sz=1<<n;
for(int i=0;i<sz;i++)scanf("%lf",&a[i]);
for(int mid=1;mid<sz;mid<<=1)
for(int j=0;j<sz;j+=(mid<<1))
for(int i=0;i<mid;i++)a[j+i+mid]+=a[j+i];
for(int i=1;i<sz;i++){
cnt[i]=cnt[i>>1]+(i&1);
double val=1-a[(sz-1)^i];
if(val<1e-8)return puts("INF"),0;
if(cnt[i]&1)ans+=1/val;
else ans-=1/val;
}
printf("%.10lf",ans);
}
例题3
题面好像很诡异,实际上推一推式子 f f f 就是 f 0 = 0 , f 1 = 1 f_0=0,f_1=1 f0=0,f1=1, f i = 2 f i − 1 + f i − 2 ( i > 2 ) f_i=2f_{i-1}+f_{i-2}(i>2) fi=2fi−1+fi−2(i>2),是一个类似斐波那契数的东西。
斐波那契数列有个性质: gcd ( f n , f m ) = f gcd ( n , m ) \gcd(f_n,f_m)=f_{\gcd(n,m)} gcd(fn,fm)=fgcd(n,m),证明在这里,事实上我们可以用一样的流程证明出这个性质在这个数列上也是成立的,这个性质下面会用到。
根据题意,
g
n
=
lcm
{
f
1
,
f
2
,
.
.
.
,
f
n
}
g_n=\text{lcm}\{f_1,f_2,...,f_n\}
gn=lcm{f1,f2,...,fn},注意到
lcm
\text{lcm}
lcm 相当于对指数取
max
\max
max,这就能联想到Min-Max容斥,转化成
min
\min
min 的话就相当于求
gcd
\gcd
gcd,令
U
=
{
f
1
,
f
2
,
.
.
.
,
f
n
}
U=\{f_1,f_2,...,f_n\}
U={f1,f2,...,fn},那么容斥式子就是:
lcm
(
U
)
=
∏
S
⊆
U
gcd
(
S
)
(
−
1
)
∣
S
∣
+
1
\text{lcm}(U)=\prod_{S\subseteq U} \gcd(S)^{(-1)^{|S|+1}}
lcm(U)=S⊆U∏gcd(S)(−1)∣S∣+1
令
D
D
D 为
S
S
S 内所有
f
f
f 的下标的集合,利用上面的那个性质,可以知道
gcd
(
S
)
=
f
gcd
(
D
)
\gcd(S)=f_{\gcd(D)}
gcd(S)=fgcd(D),代入得:
lcm
(
U
)
=
∏
S
⊆
U
f
gcd
(
D
)
(
−
1
)
∣
S
∣
+
1
=
∏
i
=
1
n
f
i
∑
S
⊆
U
[
gcd
(
D
)
=
i
]
(
−
1
)
∣
S
∣
+
1
\begin{aligned} \text{lcm}(U)&=\prod_{S\subseteq U} f_{\gcd(D)}^{(-1)^{|S|+1}}\\ &=\prod_{i=1}^n f_i^{\sum_{S\subseteq U}[\gcd(D)=i](-1)^{|S|+1}} \end{aligned}
lcm(U)=S⊆U∏fgcd(D)(−1)∣S∣+1=i=1∏nfi∑S⊆U[gcd(D)=i](−1)∣S∣+1
令 F i = ∑ S ⊆ U [ gcd ( D ) = i ] ( − 1 ) ∣ S ∣ + 1 , G i = ∑ i ∣ d f d = ∑ S ⊆ U [ i ∣ gcd ( D ) ] ( − 1 ) ∣ S ∣ + 1 F_i=\sum_{S\subseteq U}[\gcd(D)=i](-1)^{|S|+1},G_i=\sum_{i|d}f_d=\sum_{S\subseteq U}[i|\gcd(D)](-1)^{|S|+1} Fi=∑S⊆U[gcd(D)=i](−1)∣S∣+1,Gi=∑i∣dfd=∑S⊆U[i∣gcd(D)](−1)∣S∣+1。
观察 G i G_i Gi 的这个容斥式子,想要 [ i ∣ gcd ( D ) ] [i|\gcd(D)] [i∣gcd(D)] 不为 0 0 0 那么 D D D 内只能包含 i i i 的倍数,假定里面只有 i i i 的倍数,那么就可以忽略这个东西了,变成 ∑ S ⊆ U ( − 1 ) ∣ S ∣ + 1 \sum_{S\subseteq U}(-1)^{|S|+1} ∑S⊆U(−1)∣S∣+1。
根据一个众所周知的容斥trick: ∑ S ⊆ U ( − 1 ) ∣ S ∣ + 1 = [ U = ∅ ] \sum_{S\subseteq U}(-1)^{|S|+1}=[U=\empty] ∑S⊆U(−1)∣S∣+1=[U=∅],显然 n n n 以内 i i i 的倍数个数大于 1 1 1 所以 U U U 不为空集,则式子应该为 0 0 0,但是注意到原式子中 D D D 是不能为空集的,所以又要加上 1 1 1,所以有 ∀ i ∈ [ 1 , n ] , G i = 1 \forall i\in[1,n],G_i=1 ∀i∈[1,n],Gi=1。
有了这么优美的性质,再往
F
,
G
F,G
F,G 上套一个莫比乌斯反演想必能求出很好的东西:
F
i
=
∑
i
∣
d
μ
(
d
i
)
G
d
=
∑
i
∣
d
μ
(
d
i
)
F_i=\sum_{i|d} \mu(\frac d i)G_d=\sum_{i|d}\mu(\frac d i)
Fi=i∣d∑μ(id)Gd=i∣d∑μ(id)
带回去:
=
∏
i
=
1
n
f
i
∑
i
∣
d
μ
(
d
i
)
=
∏
i
=
1
n
∏
i
∣
d
f
i
μ
(
d
i
)
=
∏
d
=
1
n
∏
i
∣
d
f
i
μ
(
d
i
)
\begin{aligned} &=\prod_{i=1}^n f_i^{\sum_{i|d}\mu(\frac d i)}\\ &=\prod_{i=1}^n\prod_{i|d}f_i^{\mu(\frac d i)}\\ &=\prod_{d=1}^n\prod_{i|d}f_i^{\mu(\frac d i)} \end{aligned}
=i=1∏nfi∑i∣dμ(id)=i=1∏ni∣d∏fiμ(id)=d=1∏ni∣d∏fiμ(id)
那么 g g g 就相当于对 ∏ i ∣ d f i μ ( d i ) \prod_{i|d}f_i^{\mu(\frac d i)} ∏i∣dfiμ(id) 求前缀积,可以 O ( n ln n ) O(n\ln n) O(nlnn) 预处理出来。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 1000010
int T,n,mod;
int prime[maxn],t=0,mu[maxn];
bool v[maxn];
void SieveInit(){
mu[1]=1;
for(int i=2;i<=maxn-10;i++){
if(!v[i])prime[++t]=i,mu[i]=-1;
for(int j=1;j<=t&&i*prime[j]<=maxn-10;j++){
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
}
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
void reduce(int &x){x+=x>>31&mod;}
int f[maxn],invf[maxn],g[maxn],ans=0;
int main()
{
SieveInit();
scanf("%d",&T);while(T--)
{
scanf("%d %d",&n,&mod);
f[0]=0;f[1]=1;
for(int i=2;i<=n;i++)
reduce(f[i]=2*f[i-1]%mod+f[i-2]-mod);
for(int i=1;i<=n;i++)
invf[i]=ksm(f[i],mod-2);
for(int i=1;i<=n;i++)g[i]=1;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i){
if(mu[j/i]==1)g[j]=1ll*g[j]*f[i]%mod;
else if(mu[j/i]==-1)g[j]=1ll*g[j]*invf[i]%mod;
}
for(int i=2;i<=n;i++)g[i]=1ll*g[i-1]*g[i]%mod;
ans=0;for(int i=1;i<=n;i++)
reduce(ans+=1ll*g[i]*i%mod-mod);
printf("%d\n",ans);
}
}
扩展Min-Max容斥
原来是求 max { U } \max\{U\} max{U},现在要求 max k t h { U } \max_{kth}\{U\} maxkth{U},也就是第 k k k 大。
先上式子,依然是很优美的:
max
k
t
h
{
U
}
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
−
k
(
∣
S
∣
−
1
k
−
1
)
min
{
S
}
\text{max}_{kth}\{U\}=\sum_{S\subseteq U}(-1)^{|S|-k}\binom {|S|-1} {k-1}\min\{S\}
maxkth{U}=S⊆U∑(−1)∣S∣−k(k−1∣S∣−1)min{S}
先不管这个式子是如何推出来的,考虑如何像上面的式子一样简单优美地证明:
当 ∣ S ∣ < k |S|<k ∣S∣<k 时,求出来的 min \min min 是有可能比第 k k k 大要更大的,这我不想要,我们只要小于等于第 k k k 大的来做容斥,像上面一样,所以 ∣ S ∣ |S| ∣S∣ 要大于等于 k k k,不然上面的组合数就会变成 0 0 0 让他没有贡献。
当
∣
S
∣
≥
k
|S|\geq k
∣S∣≥k 时,假设最小值是第
i
i
i 大,剩下
∣
S
∣
−
1
|S|-1
∣S∣−1 个就只能从比
i
i
i 大的
i
−
1
i-1
i−1 个里面选,方案数为
(
∣
S
−
1
∣
i
−
1
)
\binom {|S-1|} {i-1}
(i−1∣S−1∣),总的系数为:
∑
∣
S
∣
=
k
i
(
−
1
)
∣
S
∣
−
k
(
∣
S
∣
−
1
k
−
1
)
(
i
−
1
∣
S
∣
−
1
)
=
(
i
−
1
k
−
1
)
∑
∣
S
∣
=
k
i
(
−
1
)
∣
S
∣
−
k
(
i
−
k
∣
S
∣
−
k
)
=
(
i
−
1
k
−
1
)
∑
j
=
0
i
−
k
(
−
1
)
j
(
i
−
k
j
)
=
(
i
−
1
k
−
1
)
[
i
−
k
=
0
]
\begin{aligned} &\sum_{|S|=k}^i (-1)^{|S|-k} \binom {|S|-1} {k-1}\binom {i-1} {|S|-1}\\ &=\binom {i-1} {k-1}\sum_{|S|=k}^i (-1)^{|S|-k} \binom {i-k} {|S|-k}\\ &=\binom {i-1} {k-1}\sum_{j=0}^{i-k} (-1)^j \binom {i-k} j\\ &=\binom {i-1} {k-1}[i-k=0]\\ \end{aligned}
∣S∣=k∑i(−1)∣S∣−k(k−1∣S∣−1)(∣S∣−1i−1)=(k−1i−1)∣S∣=k∑i(−1)∣S∣−k(∣S∣−ki−k)=(k−1i−1)j=0∑i−k(−1)j(ji−k)=(k−1i−1)[i−k=0]
当 i = k i=k i=k 时,贡献为 1 1 1,否则为 0 0 0。这样就达到了恰好统计第 k k k 大的目的。
证明是简单,但是做题的时候先猜个式子然后再尝试证明的一定不是正常人,上面这个证明只是为了方便记忆式子,所以还是要讲讲这个式子的来历。
一开始我们还不知道要加个什么系数,先设为
f
∣
S
∣
f_{|S|}
f∣S∣,那么式子为:
max
k
t
h
{
U
}
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
+
1
f
∣
S
∣
min
{
S
}
\text{max}_{kth}\{U\}=\sum_{S\subseteq U}(-1)^{|S|+1} f_{|S|} \min\{S\}
maxkth{U}=S⊆U∑(−1)∣S∣+1f∣S∣min{S}
我们的目标是,当
min
{
S
}
=
i
,
i
=
k
\min\{S\}=i,i=k
min{S}=i,i=k 时,总系数为
1
1
1,否则为
0
0
0,即:
∑
∣
S
∣
=
k
i
(
−
1
)
∣
S
∣
+
1
f
∣
S
∣
(
i
−
1
∣
S
∣
−
1
)
=
[
i
=
k
]
\sum_{|S|=k}^i (-1)^{|S|+1}f_{|S|}\binom {i-1} {|S|-1}=[i=k]
∣S∣=k∑i(−1)∣S∣+1f∣S∣(∣S∣−1i−1)=[i=k]
里面的组合数就是钦定 min { S } = \min\{S\}= min{S}= 第 i i i 大, S S S 的选择方案数。
后面的东西可以看成一个函数
g
i
=
[
i
=
k
]
g_i=[i=k]
gi=[i=k],那这个东西是可以套二项式反演的:
f
i
=
∑
j
=
k
i
(
−
1
)
j
+
1
(
i
−
1
j
−
1
)
g
j
=
(
−
1
)
k
+
1
(
i
−
1
k
−
1
)
\begin{aligned} f_i&=\sum_{j=k}^i(-1)^{j+1}\binom {i-1} {j-1}g_j\\ &=(-1)^{k+1}\binom {i-1} {k-1} \end{aligned}
fi=j=k∑i(−1)j+1(j−1i−1)gj=(−1)k+1(k−1i−1)
这样就求出来了,带回去就得到了:
max
k
t
h
{
U
}
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
−
k
(
∣
S
∣
−
1
k
−
1
)
min
{
S
}
\text{max}_{kth}\{U\}=\sum_{S\subseteq U}(-1)^{|S|-k}\binom {|S|-1} {k-1}\min\{S\}
maxkth{U}=S⊆U∑(−1)∣S∣−k(k−1∣S∣−1)min{S}
(关于 − 1 -1 −1 的指数——显然加上 k + 1 k+1 k+1 和减去 k + 1 k+1 k+1 是一样的,后者更好看些qwq)
以及,扩展Min-Max容斥也是可以使用在期望上的。
例题4
说是例题,好像用到扩展Min-Max容斥的网上一共就一题……
令 U = { a 1 , a 2 , . . . , a n } U=\{a_1,a_2,...,a_n\} U={a1,a2,...,an}, a i a_i ai 为第 i i i 种原料收集到的时间,那么答案为 E ( min k t h ( U ) ) E(\min_{kth}(U)) E(minkth(U))。
但是套个扩展Min-Max容斥后,会变成求 E ( max ( S ) ) E(\max(S)) E(max(S)),众所周知 max \max max 是不好求的,所以我们将 k k k 变成 n − k + 1 n-k+1 n−k+1,答案变成 E ( max k t h ( U ) ) E(\max_{kth}(U)) E(maxkth(U)),套个扩展Min-Max容斥后变成求 E ( min ( S ) ) E(\min(S)) E(min(S))。
发现 E ( min ( S ) ) E(\min(S)) E(min(S)) 是很好求的,令 g S = ∑ i ∈ S p i g_S=\sum_{i\in S} p_i gS=∑i∈Spi,那么 E ( min ( S ) ) = m g S E(\min(S))=\dfrac m {g_S} E(min(S))=gSm。
那么剩下的问题就是统计答案了,即计算:
E
(
max
k
t
h
(
U
)
)
=
∑
S
⊆
U
(
−
1
)
∣
S
∣
−
k
(
∣
S
∣
−
1
k
−
1
)
E
(
min
{
S
}
)
E(\text{max}_{kth}(U))=\sum_{S\subseteq U} (-1)^{|S|-k} \binom {|S|-1} {k-1} E(\min\{S\})
E(maxkth(U))=S⊆U∑(−1)∣S∣−k(k−1∣S∣−1)E(min{S})
考虑dp,令 f i , j , k f_{i,j,k} fi,j,k 表示前 i i i 种原料, g S g_S gS 的值为 j j j, k k k 的值为 k k k 时上面式子的和。你可能会疑惑为什么不需要记录 ∣ S ∣ |S| ∣S∣,为什么要记录 k k k,这个你看了转移就懂了。
转移就是考虑第 i i i 种原料要不要。
- 不要,就是 f i , j , k = f i − 1 , j , k f_{i,j,k}=f_{i-1,j,k} fi,j,k=fi−1,j,k;
- 要,那么 ∣ S ∣ |S| ∣S∣ 加一,因为 ( − 1 ) ∣ S ∣ − k (-1)^{|S|-k} (−1)∣S∣−k 的存在所以要取贡献的相反数,而因为 ( ∣ S ∣ − 1 k − 1 ) \binom {|S|-1} {k-1} (k−1∣S∣−1) 中 ∣ S ∣ |S| ∣S∣ 加了 1 1 1,根据组合数的递推式,有 ( ∣ S ∣ k − 1 ) = ( ∣ S ∣ − 1 k − 1 ) + ( ∣ S ∣ − 1 k − 2 ) \binom {|S|} {k-1}=\binom {|S|-1} {k-1}+\binom {|S|-1} {k-2} (k−1∣S∣)=(k−1∣S∣−1)+(k−2∣S∣−1),所以 f i , j , k = f i − 1 , j , k − f i − 1 , j − p i , k + f i − 1 , j − p i , k − 1 f_{i,j,k}=f_{i-1,j,k}-f_{i-1,j-p_i,k}+f_{i-1,j-p_i,k-1} fi,j,k=fi−1,j,k−fi−1,j−pi,k+fi−1,j−pi,k−1。(注意到 ( ∣ S ∣ − 1 k − 2 ) \binom {|S|-1} {k-2} (k−2∣S∣−1) 中 ∣ S ∣ |S| ∣S∣ 和 k k k 相对 f i , j , k f_{i,j,k} fi,j,k 同时减 1 1 1,所以贡献依然是正的)
- 特别情况:如果选择了
要
,而 j = p i j=p_i j=pi,那么在此前 ∣ S ∣ = 0 |S|=0 ∣S∣=0, ( ∣ S ∣ − 1 k − 1 ) \binom {|S|-1} {k-1} (k−1∣S∣−1) 自然也为 0 0 0,此时转移不能用组合数递推公式,得手动给他个 1 1 1,或者说贪一手方便,把 f 0 , 0 , k f_{0,0,k} f0,0,k 给设成 − 1 -1 −1qwq……
答案的话,就是 ∑ f n , j , k × m j \sum f_{n,j,k}\times \dfrac m j ∑fn,j,k×jm。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define mod 998244353
int n,K,m;
int f[10010][11],ans=0;
void reduce(int &x){x+=x>>31&mod;}
int inv[10010];
int main()
{
scanf("%d %d %d",&n,&K,&m);K=n-K+1;
for(int i=1;i<=K;i++)f[0][i]=mod-1;
for(int i=1,p;i<=n;i++){
scanf("%d",&p);
for(int k=K;k>=1;k--)
for(int j=m;j>=p;j--){
reduce(f[j][k]-=f[j-p][k]),
reduce(f[j][k]+=f[j-p][k-1]-mod);
}
}
inv[1]=1;for(int i=2;i<=m;i++)
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int j=1;j<=m;j++)
reduce(ans+=1ll*f[j][K]*inv[j]%mod-mod);
ans=1ll*ans*m%mod;
printf("%d",ans);
}