1 条题解
-
0
题解:
- 有 ( N ) 段墙,每段墙的高度可以是 ( a_i ) 或 ( b_i )。
- 对于一种高度选择方案,水位计算方式为:
- 位置 ( i ) 的水位 = 从它向左延伸到某个 ( l ),向右延伸到某个 ( r ),使得 ( h_l \ge h ) 且 ( h_r \ge h ) 的最大 ( h )。
- 特别地,位置 1 和 N 的水位等于墙高。
- 积水 = 水位 - 墙高。
- 要求:对所有 ( 2^N ) 种可能的高度选择,计算它们的 总积水量之和,并取模 ( 10^9+7 )。
关键思路
1. 水位与墙高的关系
对于一段墙 ( i ),它的水位实际上等于: [ \text{waterlevel}[i] = \min\left( \max_{j \le i} h_j, \max_{k \ge i} h_k \right) ] 因为水位是由它左边最高和右边最高两者中的较小值决定的。
所以: [ \text{积水}[i] = \min\left( \max_{j \le i} h_j, \max_{k \ge i} h_k \right) - h_i ]
2. 问题转化
我们要计算: [ \sum_{\text{所有方案}} \sum_{i=1}^N \left[ \min\left( \max_{j \le i} h_j, \max_{k \ge i} h_k \right) - h_i \right] ]
可以拆成: [ \sum_{\text{所有方案}} \sum_{i=1}^N \min\left( \max_{j \le i} h_j, \max_{k \ge i} h_k \right) - \sum_{\text{所有方案}} \sum_{i=1}^N h_i ]
3. 分别计算
3.1 第二部分:所有方案中所有墙高之和
对于位置 ( i ),它在所有方案中出现的次数是 ( 2^{N-1} ) 次(因为其它位置任意),并且每次出现的高度要么是 ( a_i ) 要么是 ( b_i ),概率均等。
所以: [ \sum_{\text{所有方案}} \sum_{i=1}^N h_i = 2^{N-1} \sum_{i=1}^N (a_i + b_i) ]
3.2 第一部分:所有方案中所有位置的水位之和
对于位置 ( i ),它的水位是: [ \min\left( \max_{j \le i} h_j, \max_{k \ge i} h_k \right) ]
我们要对所有方案求和。
4. 计算水位贡献
考虑固定位置 ( i ),我们想计算在所有方案中,它的水位值之和。
设:
- ( L = \max_{j \le i} h_j )
- ( R = \max_{k \ge i} h_k )
- 水位 = ( \min(L, R) )
我们可以枚举 ( x )(水位值),计算水位 (\ge x) 的方案数,然后累加得到水位之和。
4.1 水位 ≥ x 的条件
水位 ≥ x 当且仅当:
- 存在 ( l \le i ) 且 ( h_l \ge x )
- 存在 ( r \ge i ) 且 ( h_r \ge x )
因为这样才能保证 ( L \ge x ) 且 ( R \ge x ),从而 ( \min(L,R) \ge x )。
4.2 容斥计算方案数
设:
- ( p_j ) = 位置 ( j ) 的高度 ≥ x 的概率(在随机选择 ( a_j ) 或 ( b_j ) 时)。
- 如果 ( a_j \ge x ) 且 ( b_j \ge x ),则 ( p_j = 1 )
- 如果 ( a_j \ge x ) 且 ( b_j < x ),则 ( p_j = 1/2 )
- 如果 ( a_j < x ) 且 ( b_j \ge x ),则 ( p_j = 1/2 )
- 如果 ( a_j < x ) 且 ( b_j < x ),则 ( p_j = 0 )
那么:
- 事件 A = 左边存在高度 ≥ x:概率 = ( 1 - \prod_{j=1}^i (1 - p_j) )
- 事件 B = 右边存在高度 ≥ x:概率 = ( 1 - \prod_{j=i}^N (1 - p_j) )
水位 ≥ x 的概率 = ( P(A \cap B) )。
4.3 利用线性性求和
我们想要: [ \sum_{\text{方案}} \text{水位}(i) = \sum_{x \ge 1} #{\text{方案} \mid \text{水位}(i) \ge x} ] 因为水位是整数。
所以: [ \text{水位和} = \sum_{x=1}^{\max a_i,b_i} \text{方案数}(水位(i) \ge x) ] 方案数 = ( 2^N \times P(\text{水位}(i) \ge x) )。
5. 高效计算
直接枚举 ( x ) 从 1 到 ( 10^9 ) 不可行。但注意到 ( p_j ) 只会在 ( x ) 跨越某个 ( a_j ) 或 ( b_j ) 时变化,所以 ( x ) 的取值只有 ( O(N) ) 个关键点。
我们可以离散化所有 ( a_i, b_i ),然后按 ( x ) 从大到小扫描,用线段树或 Fenwick 树维护前缀和后缀的 ( 1-p_j ) 乘积,以及乘积之和的更新。
6. 最终算法
- 离散化所有 ( a_i, b_i ) 得到关键值 ( v_1 < v_2 < \dots < v_m )。
- 对每个位置 ( i ),预处理它在每个 ( v_t ) 处的 ( p_{i,t} )。
- 按 ( x ) 从大到小处理:
- 更新每个位置 ( i ) 的 ( 1-p_i ) 值。
- 维护前缀乘积 ( \text{pref}[i] = \prod_{j=1}^i (1-p_j) ) 和后缀乘积 ( \text{suff}[i] = \prod_{j=i}^N (1-p_j) )。
- 对每个 ( i ),计算 ( P(\text{水位} \ge x) = 1 - \text{pref}[i] - \text{suff}[i] + \text{pref}[i] \cdot \text{suff}[i] )(容斥)。
- 累加贡献。
- 得到第一部分总和,减去第二部分总和,取模。
7. 时间复杂度
- 离散化 ( O(N \log N) )
- 扫描 ( O(N \log N) )(使用 Fenwick 树维护乘积)
C 语言实现框架
由于代码较长,这里给出核心框架,省略一些细节:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define MOD 1000000007 #define MAXN 500005 typedef long long ll; int N; int a[MAXN], b[MAXN]; int vals[2*MAXN], vcnt; int posA[MAXN], posB[MAXN]; // 离散化后的位置 // 快速幂 ll powmod(ll a, ll e) { ll res = 1; while (e) { if (e & 1) res = res * a % MOD; a = a * a % MOD; e >>= 1; } return res; } // Fenwick 树维护前缀后缀乘积 ll pref[2*MAXN], suff[2*MAXN]; ll inv2; void update(ll *bit, int i, ll val) { for (; i <= N; i += i & -i) bit[i] = bit[i] * val % MOD; } ll query(ll *bit, int i) { ll res = 1; for (; i; i -= i & -i) res = res * bit[i] % MOD; return res; } int main() { inv2 = powmod(2, MOD-2); scanf("%d", &N); for (int i = 1; i <= N; i++) { scanf("%d", &a[i]); vals[vcnt++] = a[i]; } for (int i = 1; i <= N; i++) { scanf("%d", &b[i]); vals[vcnt++] = b[i]; } // 离散化 // 排序去重 vals... // 预处理每个位置在每个值处的 p // 这里简化,直接扫描... // 初始化 Fenwick for (int i = 1; i <= N; i++) { pref[i] = 1; suff[i] = 1; } ll total = 0; // 按 x 从大到小扫描 for (int k = vcnt-1; k >= 0; k--) { int x = vals[k]; // 更新所有位置 p 值变化 // 更新 Fenwick // 计算每个 i 的 P(水位 >= x) // 累加 total += 方案数 } // 第二部分 ll sumH = 0; for (int i = 1; i <= N; i++) sumH = (sumH + a[i] + b[i]) % MOD; ll part2 = powmod(2, N-1) * sumH % MOD; ll ans = (total - part2 + MOD) % MOD; printf("%lld\n", ans); return 0; }
总结
这道题的关键是:
- 理解水位 = min(左边最大, 右边最大)
- 用概率和容斥计算方案数
- 离散化 + 扫描线 + 数据结构维护乘积
由于 N 可达 5e5,必须用 O(N log N) 的算法。
- 1
信息
- ID
- 4911
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7.5
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者