[高端操作]min-max 容斥

记 $min\{S\}$ 为集合 $S$ 中最小值,$max\{S\}$ 为集合 $S$ 中最大值

则有 $max\{S\}=\sum\limits_{T \subseteq S,T \neq \emptyset}(-1)^{|T|-1}min\{T\}$

这个东西可以用来求“全都出现的期望时间”

hdu4336 Card Collector

有 n 种卡片,每秒你有 $P_i$ 的概率获得第 $i$ 张卡片,求获得所有卡片至少一张的期望时间

$n \leq 20$

sol:

直接套上面那个式子,令 $max\{S\}$ 为得到 $S$ 集合中最晚的一张的期望时间,易得这也是得到 $S$ 集合的期望时间

然后套一下式子,就只用对于 $S$ 的每一个子集 $T$ ,计算出至少得到一个 $T$ 中元素的期望时间

易得 $min\{T\}=\frac{1}{\sum\limits_{i \in T}P_i}$

然后就做完了

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
int n;double p[25],ans;
void dfs(int x,double e,int opt)
{
    if(x > n)
    {
        if(e > 1e-7)ans += opt / e;
        return;
    }
    dfs(x + 1,e,opt);
    dfs(x + 1,e + p[x],-opt);
}
int main()
{
    while(scanf("%d",&n) != EOF)
    {
        for(int i=1;i<=n;i++)cin >> p[i];
        ans = 0;dfs(1,0,-1);
        printf("%.6lf\n",ans);
    }
}
View Code

PKUWC2018 随机游走

一棵树,你从 $x$ 出发随机走,$q$ 次询问,每次给定一个点集 $S$,求走完 $S$ 的期望时间

$n \leq 18,q \leq 5000$

sol:

根据上一题的套路,我们要求对于每个子集 $T$,至少走到 $T$ 中的一个点的期望步数

然后根据不知道在哪(???)知道的套路,树上期望题可以记 $f_{(x,S)}$ 表示从 $x$ 开始走,第一次走到 $S$ 中的一个元素的期望步数

考虑这个 $f_{(x,S)}$ 怎么推,如果 $x \in S$,则 $f_{(x,S)} = 0$,如果不是的话,$f_{(x,S)} = \frac{1}{d_x} \times \sum f_{(y,S)} + 1$

然后发现 $f_{(x,S)}=a_x \times f_{(fa_x,S)} + b_x$ ,从 $0$ 的点向上推出每个 $a,b$ 即可

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int mod = 998244353,maxn = (1 << 20);
int n,q,x,d[maxn],f[maxn],k[maxn],b[maxn],fa[maxn];
vector<int> G[30];
inline int ksm(int x,int t)
{
    int res = 1;
    while(t)
    {
        if(t & 1) res = 1LL * res * x % mod;
        x = 1LL * x * x % mod;
        t = t >> 1;
    }return res;
}
inline void dfs(int x,int S)
{
    if(S & (1 << (x - 1)))
    {
        k[x] = b[x] = 0;
        return;
    }
    k[x] = b[x] = d[x];
    for(auto to : G[x])
    {
        if(to == fa[x])continue;
        fa[to] = x;dfs(to,S);
        k[x] = (mod - k[to] + k[x]) % mod;
        b[x] = (b[to] + b[x]) % mod;
    }
    k[x] = ksm(k[x],mod - 2);
    b[x] = 1LL * b[x] * k[x] % mod;
}
int main()
{
    n = read();q = read();x = read();
    for(int i=2;i<=n;i++)
    {
        int u = read(),v = read();
        G[u].push_back(v);d[u]++; 
        G[v].push_back(u);d[v]++;
    }
    for(int S=1;S<(1 << n);S++)
    {
        dfs(x,S);
        f[S] = b[x];
    }
    while(q--)
    {
        int nq = read(),S = 0;
        for(int i=1;i<=nq;i++)S = S | (1 << (read() - 1));
        LL ans = 0;
        for(int ps=S;ps;ps=(ps-1)&S)
        {
            int cnt = __builtin_popcount(ps);
            ans = (ans + ((cnt & 1) ? 1 : -1) * f[ps] + mod) % mod;
        }cout<<ans<<endl;
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/Kong-Ruo/p/10184329.html
今日推荐