Part1:(min-max) 容斥的引入
我们设有一个全集(U={a_1,a_2,dots,a_n}),我们记(min S=minlimits_{a_iin S}a_i),(max S=maxlimits_{a_iin S}a_i),假设我们可以轻易地得到(min S),但很难求得(max S),此时,为求(S),我们就要引入(mathbf{min})-(mathbf{max})容斥.
我们有以下关系:
这个式子被称为(mathbf{min})-(mathbf{max})容斥公式.我们下面来证明这个结论.
假设(max S)具有形式
其中(f(k))是容斥系数.我们考虑(k+1)大的元素会被统计到的贡献,即那些子集的最小值会为第(k+1)的元素.则
二项式反演得
得到
即
综上,
当然,也可以把式子中的(max)与(min)互换,得到(min-max)容斥的另一种形式:
证明类似.
另外,(min-max)容斥公式在期望意义下也成立.设全集(U={X_1,X_2,dots,X_n})是由两两不相关的随机变量构成的集合,并且其期望(E(X_1),E(X_2),dots,E(X_n))均存在,则
其中(E(max S))表示(S)中元素最大值的期望.注意,若(X,Y)不相关,则(E(max{X,Y}) e max{E(X),E(Y)}),所以期望意义下的最值是很难求的,而(min-max)容斥给了我们一个有力的工具.
举个栗子,假设有随机试验(E),样本空间为(S={0,1})(其意义可理解为抛硬币),(X=X(e),Y=Y(e))是这个样本空间上的两个不相关随机变量,易知(E(X)=E(Y)=1/2),那么令(Z=max(X,Y)),则(Z)的分布律为
因此(E(Z)=4/3).但(max{E(X),E(Y)}=0.5),所以期望与(max)/(min)是不相容的.
Part2:(kmathrm{th}min-max)容斥
我们要求第(k)大,怎么求呢?
我们仍然用上面的证明方法,假设其具有如下形式:
设一个元素(a)排名为第(m)大,那么有且只有不包含比它小的(n-m+1)个元素时,(min T=a).若有(m-1)个元素可供随意选择,那么必然选择(a).于是得
二项式反演得
所以
因此,
同样的,
上述公式也对期望成立.
Part3:例题
LG P3175 [HAOI2015]按位或
由于或运算时每个位都是独立的,我们可以把每个位分开来看.我们设(a_k)为第(k)个为变为(1)的时间,那么我们要求的就是(E(max U))((U)为全集).
那么,怎么求(min S)((Ssubseteq U))呢?
为了方便,我们形式地记(P(S))为选中(S)子集的概率值和.那么,(min S=k)的概率就是,前(k-1)次选了(ar S)的子集,最后一次不选(ar S)子集的概率.于是得
其中(Soplus U)表示(S)与(U)的位运算卷积.我们可以发现(min S)服从参数为(1-P(Soplus U))的几何分布,那么,
易知(P(S)=sum_{Tsubseteq S}P{T ext{被选中}}),直接枚举子集求即可,然后再用或运算的离散沃尔什变换求即可.时间复杂度(O(ncdot 2^n)).
C++实现如下:
int n,lim;
double p[(1<<20)+5],ans;
int main()
{
scanf("%d",&n);
lim=1<<n;
for(int i=0;i<=lim-1;++i)
scanf("%lf",p+i);
for(int i= 1;i<lim;i<<=1)
for(int j=0;j<lim;j+=i<<1)
for(int k=0;k<=i-1;++k)
p[i+j+k]+=p[j+k];
for(int i=1;i<=lim-1;++i)
{
double q=1-p[(lim-1)^i];
if(q<=1e-10)
{
puts("INF");
return 0;
}
ans+=(__builtin_popcount(i)&1?1:-1)*1.0/q;
}
printf("%.10lf
",ans);
}
LG P4707重返现世
我们设集合(S)为某些物品的集合,物品的权值为第一次出现的时间.那么,(E(min S))就是这些物品中有任意一个出现的期望时间.
若每一次得到(S)中物品的概率为(sumlimits_{iin S}p_i),那么期望的时间就是(1/sumlimits_{iin S}p_i).
(E(min S))是显然易求的.我们再来考虑题目要求的(kmathrm{th}min U).
通过(min-max)容斥易知
观察和式,变量有且只有(|T|),(E(min T)),同时(E(min T)=sumlimits_{iin T}p_i).
我们设(f(i,j,k))为前(i)选了(j)个时(sumlimits_{iin T}p_i=k)的方案数.最后只需把方案数求和再乘以对应权值,求和既得答案.转移方程是易得的:
可以考虑使用滚动数组压缩第一维空间.复杂度(O(n^2m)),可得70分.
我们考虑满分做法.可以发现每个项的贡献(=E(min T)cdot ext{与}|T| ext{相关的项}cdot ext{方案数}).我们考虑一个技巧:把维数藏在权值里.就是直接把这个式子的一部分作为权值,以减少维数.但是降维之后,由于我们把未知量强行加入了dp的权值之中,所以我们还要在状态上附加一个维数.
观察数据范围,(kle 11),那么这个新的维度就很有可能是(k)了.设(f(i,j))表示前(i)个物品,(sumlimits_{iin T}p_i=j)的((-1)^{|T|-k}inom{|T|-1}{k-1})之和.转移方程如下:
我们尝试求选物品时的转移方程.可以得到,(sum(-1)^{|T|-k}inom{|T|-1}{k-1})在加入了一个元素之后就变成(sum(-1)^{|T|-k+1}inom{|T|}{k-1}).将组合数拆开,得到
于是原式就等价于
减数就等于(f(i-1,j)).于是我们得到了正解:
设(f(i,j,k))表示前(i)个物品,(sum_{iin T}p_i=j)且(k)如所设的((-1)^{|T|-k}inom{|T|-1}{k-1})的和.根据上面的推导,有
边界条件(f(0,0,0)=1).仍使用滚动数组压缩第一维.注意有(p_i=0)的情况.
C++实现如下:
const int Mod=998244353;
const int Maxn=10107;
typedef long long LL;
LL f[Maxn][15],ans;
int n,m,t,p[Maxn];
inline LL ksm(LL a,LL b)
{
if(b==0)
return 1;
if(b==1)
return a;
LL x=ksm(a,b>>1)%Mod;
if(b&1)
return x*x%Mod*a%Mod;
return x*x%Mod;
}
int main()
{
scanf("%d%d%d",&n,&t,&m);
t=n-t+1;
for(int i=1;i<=n;++i)
scanf("%d",p+i);
f[0][0]=1;
for(int i=1;i<=n;++i)
{
if(p[i])
for(int j=m-p[i];~j;--j)
for(int k=t;k;--k)
f[j+p[i]][k]=(f[j+p[i]][k]+f[j][k-1]-f[j][k])%Mod;
}
for(int i=1;i<=m;++i)
ans+=f[i][t]*m%Mod*ksm(i,Mod-2),
ans%=Mod;
printf("%lld
",(ans+Mod)%Mod);
}