【Luogu4707】重返现世(min-max容斥)
题面
洛谷
求全集的(k-max)的期望
题解
(min-max)容斥的证明不难,只需要把所有元素排序之后考虑组合数的贡献,容斥系数先设出来后也不难解出。
那么我们来考虑如何求解(k-max),设出容斥系数(f(|T|))
显然是从小到大考虑每个元素作为(min)时候的贡献,并且我们只需要其中第(k)大的贡献。
假设(n=|S|),那么对于第(x)大的数,有:
令(x=n-x)
直接套二项式反演:
显然只有(i=k-1)的时候才有贡献,也就是:
化简后得到:
好了,带回(min-max)容斥的式子,得到:
回到这题,要求的就是(kmax(All)),发现题目中给出了限制(|n-k|le 10),但是这样子符合条件的(T)依旧很多,那么我们按照(min(T))来分类,而(min(T))之和所有(T)中元素出现的概率的和相关,所以直接大力(dp)即可。
注意一下,题目里面的(k)对应到(kmax)的时候,应该是(n-k+1),也就是第(n-k+1)大的出现时间。
然后讲讲怎么(dp),设(f[i][j])表示当前选定的集合的(p)的和为(i),组合数那里(k=j)。
对于当前物品而言,只有两种选择:要么加入集合,要么不加入。
如果不加入的话显然对于答案没有影响直接(f'[i][j]
ightarrow f[i][j])。
否则的话加入这个元素之后会产生影响,考虑具体的转移究竟是什么。
首先(displaystyle f[j-p][k-1]=sum(-1)^{i-(k-1)}{i-1choose k-2}Cnt[i][j-p])。其中(Cnt[i][j])表示集合大小为(i),其概率的和为(j)的方案数。
等号右边显然就是(min-max)容斥的式子,因为要求的只是方案数,所以后面并不是(min),而是方案数。
现在要做的就是强制把一个物品塞进去。
塞进去的影响是什么呢?集合大小强制多了(1),并且概率的和增加了,并且我们假装(k)也改变了。
所以塞进去后的式子是:(displaystyle sum(-1)^{i-(k-1)}{ichoose k-1}Cnt[i][j-p])
因为组合数有简单的转移式:(displaystyle {nchoose m}={n-1choose m}+{n-1choose m-1})。
所以多出来的部分不难发现是(displaystyle -sum(-1)^{i-k}{i-1choose k-1}Cnt[i][j-p])
也就是(-f[j-p][k])。
所以转移也就是:(f[i][j]=f'[i][j]+f'[i-p][j-1]-f'[i-p][j])
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 10100
#define MOD 998244353
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,k,m,p[1010],t,ans,N,nw,pw;
int f[2][10100][15],inv[MAX];
int main()
{
n=read();k=n-read()+1;m=read();
for(int i=1;i<=n;++i)p[i]=read();
if(!k){puts("0");return 0;}
for(int i=1;i<=k;++i)f[0][0][i]=MOD-1;
nw=1;pw=0;
for(int i=1,sum=0;i<=n;nw^=1,pw^=1,sum+=p[i++])
for(int j=0;j<=sum;++j)
for(int l=1;l<=k;++l)
if(f[pw][j][l])
{
add(f[nw][j][l],f[pw][j][l]);
add(f[nw][j+p[i]][l+1],f[pw][j][l]);
add(f[nw][j+p[i]][l],MOD-f[pw][j][l]);
f[pw][j][l]=0;
}
inv[0]=inv[1]=1;for(int i=2;i<=m;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=m;++i)add(ans,1ll*f[pw][i][k]*inv[i]%MOD);
ans=1ll*ans*m%MOD;printf("%d
",ans);
return 0;
}