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=suma−ina,银币数量就是
o
u
t
b
=
s
u
m
b
−
i
n
b
out_{b}=sum_{b}-in{b}
outb=sumb−inb,要求的就是
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)>outa−ina
能够发现的是
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)=outb−poss(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+outb−ina
发现左边可以进行合并,因为
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+outb−ina
其中
o
u
t
a
+
o
u
t
b
−
i
n
a
out_{a}+out_{b}-in_{a}
outa+outb−ina是可以
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+outb−ina=i=p+1∑sumb(isumb)∗(21)sumb=(21)sumbi=p+1∑sumb(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;
}