[QOJ4533] 灯泡测试 题解

[QOJ4533] 灯泡测试 题解

如果只有两个灯泡,要求第一个灯泡比第二个灯泡早爆炸,那么答案就是:

\[\int_{-\infty}^{\infty}-f'_1(t)f_2(t)\text dt \]

因为 \(f(t)\) 表示寿命大于 \(t\) 的概率,所以它的导数的相反数就是寿命 \(= t\) 的概率。

如果有 \(n\) 个灯泡,询问 \((1, v+1)\),答案就是:

\[\begin{aligned} &\int_{-\infty}^{\infty} f'_1(t)\sum_{S\subseteq\{1, 2,...,n\},|S| = v }\prod_{i\in S} (1 - f_i(t))\prod_{i\notin S} (f_i(t))\text{d}t\\ =&\int_{-\infty}^{\infty} f'_1(t)[w^v]\prod_i(1-f_i(t)+f_i(t)w)\text{d}t\\ \end{aligned} \]

因为 \(f\) 是分段函数,我们考虑所有 \(f\) 的分割点,将实数域分为了 \(n + 1\) 部分,每一部分单独考虑,也就是说从小往大考虑所有 \(T_i\),将 \(i\) 对应的背包项从 \(w\) 改为 \(1-f_i(t)+f_i(t)w\),这里记录有多少个单独 \(w\) 的项,将多项式统一除掉这么多 \(w\) 方便计算:

\[\begin{aligned} =&\int_{T_k}^{T_{k + 1}} (e^{-\lambda_1(t - T_1)}) '[w^v]\prod_{T_i\ge k}(1-e^{-\lambda_i(t - T_i)}+e^{-\lambda_i(t - T_i)}w)\mathrm{d}t\\ =&\int_{T_k}^{T_{k + 1}} -\lambda _1e^{\lambda_1 T_1-\lambda_1t}[w^v]\prod_{T_i\ge k}(1-e^{-\lambda_it +\lambda_i T_i}+e^{-\lambda_it +\lambda_i T_i}w)\mathrm{d}t\\ =-\lambda _1e^{\lambda_1 T_1}&\int_{T_k}^{T_{k + 1}} e^{-\lambda_1t} [w^v]\prod_{T_i\ge k}(1-e^{-\lambda_it +\lambda_i T_i}+ e^{-\lambda_it +\lambda_i T_i}w)\text{d}t\\ \end{aligned} \]

发现 \(e^{-t}\) 一直出现,考虑换元为 \(x\)

\[\begin{aligned} -\lambda _1e^{\lambda_1 T_1}&\int_{T_k}^{T_{k + 1}} e^{-\lambda_1t}[w^v]\prod_i(1-e^{-\lambda_it +\lambda_i T_i}+e^{-\lambda_it +\lambda_i T_i}w)\text{d}t\\ =-\lambda _1e^{\lambda_1 T_1}&\int_{T_k}^{T_{k + 1}} e^{-\lambda_1t}[w^v]\prod_i(1-e^{-\lambda_it +\lambda_i T_i}+e^{-\lambda_it +\lambda_i T_i}w)\dfrac {\text{d}t}{\text d(e^{-t})}\text d(e^{-t})\\ =-\lambda _1e^{\lambda_1 T_1}&\int_{T_k}^{T_{k + 1}} e^{-\lambda_1t}[w^v]\prod_i(1-e^{-\lambda_it +\lambda_i T_i}+e^{-\lambda_it +\lambda_i T_i}w) \dfrac 1{-e^{-t}}\text d(e^{-t})\\ =-\lambda _1e^{\lambda_1 T_1}&\int_{e^{-T_{k +1}}}^{e^{-T_k}} x^{\lambda_1}[w^v]\prod_i(1-x^{\lambda_i}e^{\lambda_iT_i}+x^{\lambda_i}e^{\lambda_iT_i}w) (-\dfrac 1{x})\text dx\\ =\lambda _1e^{\lambda_1 T_1}&\int_{e^{-T_{k +1}}}^{e^{-T_k}} x^{\lambda_1-1}[w^v]\prod_i(1-x^{\lambda_i}e^{\lambda_iT_i}+x^{\lambda_i}e^{\lambda_iT_i}w) \text dx\\ \end{aligned} \]

用二维背包维护连乘式,设连乘式乘上 \(x^{\lambda _1 - 1}\) 和前文所少乘的 \(w\) 代表的二元多项式为 \(A\),容易计算出 \(f_{i, j} = [x^iw^j]A\)

\[\begin{aligned} \lambda _1e^{\lambda_1 T_1}&\int_{e^{-T_{k +1}}}^{e^{-T_k}} [w^v]\sum_{u, v}f_{u, v}x^uw^v\ \text dx\\ =\lambda _1e^{\lambda_1 T_1}&\int_{e^{-T_{k +1}}}^{e^{-T_k}} \sum_{u}f_{u, v}x^u\ \text dx\\ =\lambda _1e^{\lambda_1 T_1}&\sum_{u}f_{u, v}\int_{e^{-T_{k +1}}}^{e^{-T_k}} x^u\ \text dx\\ \end{aligned} \]

后面积分的原函数一目了然,使用牛顿莱布尼茨公式可以计算出上式,总的复杂度为 \(O(n^4)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define int long long
using namespace std;
typedef long double ld;
const int N = 250 + 10;
int n, q, p[N], lam[N];
ld f[N][N], T[N], ans[N][N];
signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> T[i] >> lam[i], p[i] = i;
    sort(p + 1, p + n + 1, [&](int a, int b) {return T[a] < T[b];});
    for(int I = 1; I <= n; I ++) {
        memset(f, 0, sizeof f);
        f[0][0] = 1;
        bool flg = 0;
        ld tl = lam[I] * exp(T[I] * lam[I]);
        for(int o = 1, cnt = 0, sz = 0; o <= n; o ++) {
            int i = p[o];
            ld t = exp(T[i] * lam[i]);
            if(i == I) flg = 1;
            else {
                cnt ++;
                for(int j = sz; ~j; j --) {
                    for(int k = o; ~k; k --) {
                        f[j + lam[i]][k] -= f[j][k] * t;
                        f[j + lam[i]][k + 1] += f[j][k] * t;
                    }
                }
                sz += lam[i];
            }
            if(flg) {
                for(int v = 0; v <= n; v ++) {
                    for(int j = 0; j <= sz; j ++) {
                        ans[I][v + n - 1 - cnt] += tl * f[j][v] * 
                        (exp(-T[i] * (j + lam[I])) / (j + lam[I]) - (o == n ? 0 : exp(-T[p[o + 1]] * (j + lam[I])) / (j + lam[I])));
                    }
                }
                
            }
        }
    }
    cin >> q;
    while(q --) {
        int x, v; cin >> x >> v;
        printf("%.6Lf\n", ans[x][v - 1]);
    }
    
    return 0;
} 
posted @ 2025-08-28 23:29  MoyouSayuki  阅读(26)  评论(0)    收藏  举报
:name :name