F. Rare Coins:
题目大意:
思路解析:
金币价值是固定的,银币价值是概率确定的。假如3枚银币有2的价值的概率为 C23 * (1/2) ^ 3,这个C组合数打着很麻烦,所以后面用 (2,3) 代替。
假设现在有这样一组数据 2 3 5 4,1 0 3 9, 查询1-3,那么答案的概率为:
{ (0,4) * [ (0,9) + (1,9) + .... + (5,9) ] + (1,4) * [ (0,9) + (1,9) + .... + (6,9) ] + (2,4) * [ (0,9) + (1,9) + .... + (7,9) ] + (3,4) * [ (0,9) + (1,9) + .... + (8,9) ] + (4,4) * [ (0,9) + (1,9) + .... + (9,9) ] } * (1/2) * 13
这样的概率计算是O(N)的,但是可以发现上式等价于 [ (0,13) + (1,13) + ..... + (9,13) ] * (1/2) ^ 13
我们可以发现如果都能化简成这个形式的话,那么答案就可以用前缀和处理前半部分进而使得答案计算变得容易。我们再枚举其他例子可以发现确实能满足这样的化简。
那么我们开始思考这个9应该怎么确定, 两个目标袋子的金币数差为(2+3+5)- 4 = 6, 第一个袋子银币数为 4, 总硬币数13,我们思考什么情况下会使得第一个袋子的价值大于第二个袋子。当两个袋子一起选到的 银币 k < 6 + 4 时可以满足第一个袋子的价值更高。
代码实现:
import java.io.*;
import java.math.BigInteger;
import java.util.*;
public class Main {
static int inf = (int) 2e7;
static int mod = 998244353;
public static void main(String[] args) throws IOException {
int t = 1;
while (t > 0) {
solve();
t--;
}
w.flush();
w.close();
br.close();
}
public static void solve() {
int n = f.nextInt(); int q = f.nextInt();
int[] suma = new int[n+1];
int[] sumb = new int[n+1];
for (int i = 1; i <= n; i++) {
suma[i] = suma[i-1];
suma[i] += f.nextInt();
}
for (int i = 1; i <= n; i++) {
sumb[i] = sumb[i-1];
sumb[i] += f.nextInt();
}
int m = sumb[n];
long pw = qkm(2, m);
pw = qkm(pw, mod - 2);
long[] pow = new long[m+1];
long[] inv = new long[m+1];
pow[0] = 1;
for (int i = 1; i < m+1; i++) {
pow[i] = pow[i - 1] * i % mod;
}
inv[m] = qkm(pow[m], mod - 2);
for (int i = m-1; i >= 0; i--) {
inv[i] = inv[i + 1] * (i + 1) % mod;
}
long[] sumc = new long[m+2];
for (int i = 0; i <= m; i++) {
sumc[i + 1] = (sumc[i] + (pow[m] * inv[i] % mod * inv[m - i] % mod)) % mod;
}
for (int i = 0; i < q; i++) {
int l = f.nextInt() - 1;
int r = f.nextInt();
int cur = (suma[r] - suma[l]) * 2 - suma[n];
int k = sumb[r] - sumb[l];
int mx = Math.max(0, Math.min(cur + k, m + 1));
w.print(sumc[mx] * pw % mod + " ");
}
}
public static long qkm(long a, long b){
long res = 1;
while (b > 0){
if ((b & 1) == 1) res = (res * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return res;
}
static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
static Input f = new Input(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public String nextLine() {
String str = null;
try {
str = reader.readLine();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return str;
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public Double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
}