ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU7162. Equipment Upgrade (2022杭电多校第3场1001)

2022-07-26 22:33:17  阅读:181  来源: 互联网

标签:杭电多校 Upgrade frac limits HDU7162 int res sum Lint


HDU7162. Equipment Upgrade (2022杭电多校第3场1001)

题意

有一件装备,一开始是 \(0\) 级,可以强化它,当它在第 \(i\) 级时,需要花费 \(c_i\) 强化它,有 \(p_i\) 的概率强化成功(升高一级),\(1-p_i\) 的概率强化失败(降 \(1\) 至 \(i\) 级),其中降 \(j\) 级的权重为 \(w_j\),也就是说有 \((1-p_i)\frac{w_j}{\sum\limits_{k=1}^i w_k}\) 的概率降 \(j\) 级。求从 \(0\) 级升级到 \(n\) 级的期望花费。

分析

设 \(f(i)\) 为处于第 \(i\) 级的期望代价,即要算 \(f(0)\)。

记 \(S_i=\sum\limits_{j=1}^i w_j\)

根据题意,可以写出式子

\[f(i)=p_if(i+1)+\frac{1-p_i}{S_i}\sum_{j=1}^i w_jf(i-j)+c_i \]

上面的式子后面的和式已经出现了卷积形式,但是不便于求解。

容易发现,上面式子包含 \(f(0),f(1),...,f(i+1)\)。稍作移项,得到

\[f(i+1)=\frac{f(i)-c_i-\frac{1-p_i}{S_i}\sum\limits_{j=1}^i w_jf(i-j)}{p_i} \]

这说明如果已知 \(f(0),f(1),...,f(i)\),就能线性地推出 \(f(i+1)\)

而现在已知 \(f(n)\) 是 \(0\),要求 \(f(0)\)。我们可以尝试将 \(f(i)\) 线性地用 \(f(0)\) 表示,具体地说就是设

\[f(i)=a_i f(0)+b_i \]

我们只要求出 \(a_i\) 和 \(b_i\),最终答案就是 \(-\frac{b_n}{a_n}\)

根据 \(f(i)\) 的递推式和所设 \(a_i\) 与 \(b_i\) 的含义,可以推得 \(a_i\) 和 \(b_i\) 的递推式。

\[a_{i+1}=\frac{a_i-\frac{1-p_i}{S_i}\sum\limits_{j=1}^i w_j a_{i-j}}{p_i}\\ b_{i+1}=\frac{b_i-c_i-\frac{1-p_i}{S_i}\sum\limits_{j=1}^i w_j b_{i-j}}{p_i} \]

这样就可以CDQ分治配合卷积 \(O(n\log^2n)\) 求解 \(a_i\) 和 \(b_i\) 了。

CDQ分治的时候注意 \(w_i\) 和 \(a_j\) / \(b_j\) 贡献在了 \(a_{i+j+1}\) / \(b_{i+j+1}\) 上。调用NTT卷积时,要仔细计算好相应的位置。

代码

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
namespace NTT {
typedef int Lint;
typedef long long LLint;
// 2的幂次
const int maxn = (1 << 21) + 10;
const Lint mod = 998244353;
const Lint g = 3;
Lint fpow(Lint a, Lint b, Lint mod) {
    Lint res = 1;
    for (; b; b >>= 1) {
        if (b & 1)
            res = (LLint)res * a % mod;
        a = (LLint)a * a % mod;
    }
    return res;
}
inline Lint add(Lint a, Lint b) {
    a += b;
    return a >= mod ? a - mod : a;
}
inline Lint mul(Lint a, Lint b) {
    return (LLint)a * b % mod;
}
int r[maxn];
void cal_r(int n) {
    for (int i = 0; i < n; i++) {
        r[i] = (i & 1) * (n >> 1) + (r[i >> 1] >> 1);
    }
}
void dft(Lint* a, int n, int type) {
    for (int i = 0; i < n; i++)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 1; i < n; i <<= 1) {
        int p = i << 1;
        Lint w = fpow(g, (mod - 1) / p, mod);
        if (type == -1)
            w = fpow(w, mod - 2, mod);
        for (int j = 0; j < n; j += p) {
            Lint t = 1;
            for (int k = 0; k < i; k++, t = mul(t, w)) {
                Lint tmp = mul(a[j + k + i], t);
                a[j + k + i] = add(a[j + k], mod - tmp);
                a[j + k] = add(a[j + k], tmp);
            }
        }
    }
    if (type == -1) {
        Lint inv = fpow(n, mod - 2, mod);
        for (int i = 0; i < n; i++)
            a[i] = mul(a[i], inv);
    }
}
Lint p[maxn], q[maxn];
vector<Lint> poly_mul(const vector<Lint>& a, const vector<Lint>& b) {
    vector<Lint> res;
    int n = a.size(), m = b.size();
    res.resize(n + m - 1);
    int len = n + m - 1;
    int lim = 1;
    while (lim < len)
        lim <<= 1;
    copy(a.begin(), a.end(), p);
    fill(p + n, p + lim, 0);
    copy(b.begin(), b.end(), q);
    fill(q + m, q + lim, 0);
    cal_r(lim);
    dft(p, lim, 1), dft(q, lim, 1);
    for (int i = 0; i < lim; i++)
        p[i] = mul(p[i], q[i]);
    dft(p, lim, -1);
    for (int i = 0; i < n + m - 1; i++)
        res[i] = p[i];
    return res;
}

};  // namespace NTT

int inv(int a) {
    return NTT::fpow(a, NTT::mod - 2, NTT::mod);
}
using NTT::add;
using NTT::mod;
using NTT::mul;
using NTT::poly_mul;

int n;
const int maxn = (1 << 18) + 10;
const int inv100 = 828542813;
int lim;
int w[maxn], p[maxn], sum[maxn], inv_sum[maxn], inv_p[maxn];
int a[maxn], b[maxn], c[maxn];
void solve_ab(int l, int r) {
    if (l == r) {
        if (l == 0)
            return;
        a[l] = mul(add(a[l - 1], mod - mul(add(1, mod - p[l - 1]), mul(inv_sum[l - 1], a[l]))), inv_p[l - 1]);
        b[l] = mul(add(add(b[l - 1], mod - c[l - 1]), mod - mul(add(1, mod - p[l - 1]), mul(inv_sum[l - 1], b[l]))), inv_p[l - 1]);
        return;
    }
    int mid = l + r >> 1;
    solve_ab(l, mid);

    vector<int> P(r - l), Q(mid - l + 1);

    for (int i = 0; i < r - l; i++)
        P[i] = w[i];
    for (int i = l; i <= mid; i++)
        Q[i - l] = a[i];
    vector<int> res = poly_mul(P, Q);
    for (int i = mid + 1; i <= r; i++) {
        a[i] = add(a[i], res[i - l - 1]);
    }

    for (int i = 0; i < r - l; i++)
        P[i] = w[i];
    for (int i = l; i <= mid; i++)
        Q[i - l] = b[i];
    res = poly_mul(P, Q);
    for (int i = mid + 1; i <= r; i++) {
        b[i] = add(b[i], res[i - l - 1]);
    }
    
    solve_ab(mid + 1, r);
}
void solve() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> p[i] >> c[i];
        p[i] = mul(p[i], inv100);
        inv_p[i] = inv(p[i]);
    }
    for (int i = 1; i <= n - 1; i++) {
        cin >> w[i];
        sum[i] = add(sum[i - 1], w[i]);
        inv_sum[i] = inv(sum[i]);
    }
    fill(a + 1, a + 1 + n, 0);
    fill(b + 1, b + 1 + n, 0);
    solve_ab(0, n);
    cout << mul(mod - b[n], inv(a[n])) << '\n';
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    a[0] = 1;
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

标签:杭电多校,Upgrade,frac,limits,HDU7162,int,res,sum,Lint
来源: https://www.cnblogs.com/Bamboo-Wind/p/16522926.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有