[Easy-Medium] CF1948F Rare Coins
2025/2/3约 745 字大约 4 分钟
简要题意
有 个口袋,第 个口袋里有 个金币和 个银币。
一枚金币的价值为 ;一枚银币有 的概率价值为 , 的概率价值为 。
有 次询问,每次询问给出区间 ,你需要输出区间中的所有口袋的所有钱币的价值总和,大于区间外所有口袋的钱币价值总和的概率。答案对 取模。
。
思路
大力推式子,考虑每次询问,区间内有 个金币 个银币,区间外有 个金币和 个银币,则答案为:
注意到 等价于 即 ,于是改为枚举差值,得到:
这样我们就消去了不等式的限制,对于后面的形式,稍加变形,再应用范德蒙德卷积公式,得到:
令 得到:
由于 为所有口袋的银币总数 ,是定值,于是可以预处理 为上指标的组合数后缀和,来做到预处理 ,单次 。
代码
实现忘记保存 的值了,退化为单次 。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
constexpr int mod = 998244353;
int Add(int x, int y){ return (x + y) >= mod ? (x + y - mod) : (x + y); }
int Sub(int x, int y){ return (x - y) < 0 ? (x - y + mod) : (x - y); }
int Mul(int x, int y){ return 1ll * x * y % mod; }
int fastpow(int x, int y){
int ret = 1;
for(;y;y>>=1,x=Mul(x, x)){ if(y & 1) ret = Mul(ret, x); }
return ret;
}
int n, q, a[N], b[N], fact[N], inv[N], f[N];
int binom(int n, int m){ return n < m ? 0 : Mul(fact[n], Mul(inv[m], inv[n - m])); }
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> q;
for(int i=1;i<=n;i++) cin >> a[i], a[i] += a[i - 1];
for(int i=1;i<=n;i++) cin >> b[i], b[i] += b[i - 1];
fact[0] = inv[0] = fact[1] = inv[1] = 1;
for(int i=2;i<=b[n];i++){
fact[i] = Mul(fact[i - 1], i);
inv[i] = Mul(inv[mod % i], mod - mod / i);
}
for(int i=2;i<=b[n];i++) inv[i] = Mul(inv[i - 1], inv[i]);
for(int i=b[n];~i;i--) f[i] = Add(f[i + 1], binom(b[n], i));
while(q--){
int l, r; cin >> l >> r;
int A = a[r] - a[l - 1], B = b[r] - b[l - 1], C = a[n] - A, D = b[n] - B;
int tmp = min(max(C - A + D + 1, 0), b[n] + 1);
cout << Mul(fastpow(2, mod - 1 - b[n]), f[tmp]) << ' ';
}
cout << '\n';
return 0;
}
// Written by xiezheyuan