F. Rare Coins

F. Rare Coins

题意

  给定 n n n个背包,每个包里有 a i a_{i} ai个金币和 b i b_{i} bi个银币,每个金币的价值为 1 1 1,每个银币的价值为 1 2 \frac{1}{2} 21概率为 0 0 0 1 2 \frac{1}{2} 21的概率为 1 1 1 q q q次询问,每次求 l l l r r r之间背包的价值总和比剩下的其他背包价值总和高的概率

分析

  首先前缀和算出 s u m a sum_{a} suma s u m b sum_{b} sumb,然后对于每次询问,在 l l l r r r之间的金币数量为 i n a in_{a} ina,银币数量为 i n b in_{b} inb,那么不在该区间内的金币数量就是 o u t a = s u m a − i n a out_{a}=sum_{a}-in_{a} outa=sumaina,银币数量就是 o u t b = s u m b − i n b out_{b}=sum_{b}-in{b} outb=sumbinb,要求的就是
i n a + p o s s ( i n b ) > o u t a + p o s s ( o u t b ) \begin{align} in_{a}+poss(in_{b})>out_{a}+poss(out_{b}) \end{align} ina+poss(inb)>outa+poss(outb)
移项得
p o s s ( i n b ) − p o s s ( o u t b ) > o u t a − i n a \begin{align} poss(in_{b})-poss(out_{b})>out_{a}-in_{a} \end{align} poss(inb)poss(outb)>outaina
能够发现的是
p o s s ( o u t b ) = o u t b − p o s s ( o u t b ) \begin{align} poss(out_{b})=out_{b}-poss(out_{b}) \end{align} poss(outb)=outbposs(outb)
带入得到
p o s s ( i n b ) + p o s s ( o u t b ) > o u t a + o u t b − i n a \begin{align} poss(in_{b})+poss(out_{b})>out_{a}+out_{b}-in_{a} \end{align} poss(inb)+poss(outb)>outa+outbina
发现左边可以进行合并,因为 s u m b = i n b + o u t b sum_{b}=in_{b}+out_{b} sumb=inb+outb,所以 p o s s ( i n b ) + p o s s ( o u t b ) = p o s s ( s u m b ) poss(in_{b})+poss(out_{b})=poss(sum_{b}) poss(inb)+poss(outb)=poss(sumb),化简得
p o s s ( s u m b ) > o u t a + o u t b − i n a \begin{align} poss(sum_{b})>out_{a}+out_{b}-in_{a} \end{align} poss(sumb)>outa+outbina
其中 o u t a + o u t b − i n a out_{a}+out_{b}-in_{a} outa+outbina是可以 O ( 1 ) O(1) O(1)算出来的,那么只需要计算不等式左边部分,即
p = o u t a + o u t b − i n a a n s = ∑ i = p + 1 s u m b ( s u m b i ) ∗ ( 1 2 ) s u m b = ( 1 2 ) s u m b ∑ i = p + 1 s u m b ( s u m b i ) \begin{align} p &= out_{a}+out_{b}-in_{a} \\ ans&=\sum_{i=p+1}^{sum_{b}} \binom{sum_{b}}{i}*(\frac{1}{2})^{sum_{b}} \\ &=(\frac{1}{2})^{sum_{b}} \sum_{i=p+1}^{sum_{b}} \binom{sum_{b}}{i} \end{align} pans=outa+outbina=i=p+1sumb(isumb)(21)sumb=(21)sumbi=p+1sumb(isumb)
该式子可以通过计算后缀和快速得出

AC代码

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int mod = 998244353;
LL qp(LL a, LL b) {
    LL res = 1;
    for (; b; b >>= 1, a = a * a % mod) {
        if (b & 1) {
            res = res * a % mod;
        }
    }
    return res;
}
LL fac[1000010], inv[1000010];
void Solve() {
    int n, q;
    cin >> n >> q;
    vector<int> a(n + 1), b(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
    }
    vector<LL> suma(n + 1), sumb(n + 1);
    for (int i = 1; i <= n; i++) {
        suma[i] = (suma[i - 1] + a[i]) % mod;
        sumb[i] = (sumb[i - 1] + b[i]) % mod;
    }
    vector<LL> suf(sumb[n] + 2);
    auto C = [&](LL n, LL m) {
        if (n < m || n < 0 || m < 0) {
            return 0LL;
        }
        return fac[n] * inv[m] % mod * inv[n - m] % mod;
    };
    for (int i = sumb[n]; i >= 1; i--) {
        suf[i] = (suf[i + 1] + C(sumb[n], i)) % mod;
    }
    LL iv = qp(qp(2, mod - 2), sumb[n]);
    while (q--) {
        int l, r;
        cin >> l >> r;
        LL outb = (sumb[n] - (sumb[r] - sumb[l - 1])) % mod;
        LL outa = (suma[n] - (suma[r] - suma[l - 1])) % mod;
        LL ina = (suma[r] - suma[l - 1]) % mod;
        if (outb + outa - ina < 0) {
            cout << "1 ";
            continue;
        }
        if (outb + outa - ina >= sumb[n]) {
            cout << "0 ";
        } else {
            cout << suf[outb + outa - ina + 1] % mod * iv % mod << " ";
        }
    }
    cout << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    fac[0] = fac[1] = inv[0] = inv[1] = 1;
    for (int i = 1; i <= 1000000; i++) {
        fac[i] = fac[i - 1] * i % mod;
    }
    inv[1000000] = qp(fac[1000000], mod - 2);
    for (int i = 1000000 - 1; i >= 1; i--) {
        inv[i] = inv[i + 1] * (i + 1) % mod;
    }
    int T = 1;
    // cin >> T;
    while (T--) {
        Solve();
    }
    return 0;
}
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值