min-max容斥
经典形式
结论很简单,对于一个集合S,令
证明也很容易,不妨假设最值唯一,考虑
例题:[HAOI2015]按位或
因为期望是线性的,所以上述结论在期望下也成立
令
那么答案就是
考虑怎么求
#include<bits/stdc++.h>
#define N (1 << 20) + 5
#define ld double
using namespace std;
int n,cnt[N];
ld p[N];
int main()
{
scanf("%d",&n); n = (1 << n);
for(int i=0;i<n;++i) scanf("%lf",p + i),cnt[i] = cnt[i >> 1] + (i & 1);
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=(i<<1))
for(int k=0;k<i;++k)
p[j + k + i] += p[j + k];
ld ans = 0; int s = (n - 1);
for(int i=1;i<n;++i) if(1 - p[s ^ i] > 1e-8) ans += ((cnt[i] & 1) ? 1 : -1) / (1 - p[s ^ i]);
if(ans < 1e-10) puts("INF");
else printf("%.10lf\n",ans);
return 0;
}
扩展min-max容斥
将上面的最大变成第k大:
在期望下同理,证明不会(列个式子二项式反演?)
例题:重返现世
求的是
枚举子集
令
考虑加入一个原料
如果选它,考虑贡献是多少:在没有它的所有集合
将组合数拆开可以得到
搞到这里发现k也变了,说明状态设少了,应该再加一个k
状态转移方程为:
#include<bits/stdc++.h>
#define N 1005
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int n,mx,m,now = 1,las = 0;
ll p[N],f[2][N*10][12];
ll qp(ll a,ll b) { ll ret=1; for(;b;b>>=1,a=a*a%mod) if(b & 1) ret=ret*a%mod; return ret; }
int main()
{
cin>>n>>mx>>m;
mx = n + 1 - mx;
for(int i=1;i<=n;++i) cin>>p[i];
for(int i=1;i<=n;++i)
{
swap(now,las);
for(int j=1;j<=m;++j)
{
for(int k=1;k<=mx;++k)
{
f[now][j][k] = 0;
if(j < p[i]) f[now][j][k] = f[las][j][k];
if(j == p[i]) f[now][j][k] = (f[las][j][k] + (k == 1));
if(j > p[i]) f[now][j][k] = (f[las][j][k] + f[las][j - p[i]][k - 1] - f[las][j - p[i]][k]) % mod;
}
}
}
ll ans = 0;
for(int i=1;i<=m;++i) ans = (ans + m * qp(i,mod - 2) % mod * f[now][i][mx] % mod) % mod;
cout<<(ans + mod) % mod<<endl;
return 0;
}