安吉D2-T2
1022 字
5 分钟
安吉D2-T2
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2本文
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
P11261 直方图 Histogram
题目描述
给定笛卡尔坐标系中的直方图,宽度为 ,第 格的高度为 .也就是说,对于 ,第 格所占矩形的顶点坐标分别为 .
给定正整数 ,求出满足以下条件的矩形的数量:
- 矩形的四个顶点的坐标均为整数;
- 矩形有一条边在 轴上;
- 矩形完全位于直方图内部(可以与边界相切);
- 矩形的面积至少为 .
输入格式
第一行,两个正整数 .
第二行, 个正整数 .
输出格式
输出一行一个整数,表示答案.
输入输出样例 #1
输入 #1
6 91 4 4 5 2 3输出 #1
3输入输出样例 #2
输入 #2
10 53 6 1 3 2 1 5 3 4 2输出 #2
31说明/提示
样例解释
样例一解释:

数据范围
对于 的数据,保证:
- ;
- ;
- .
| 子任务编号 | 得分 | |||
|---|---|---|---|---|
思路
由于高度最小的一项是瓶颈,考虑以高度最小的一项为中点,先计算出左端点在中点左边,右端点在中点右边的方案数,再分治,分左半边和右半边两个子问题分别考虑.
在处理子问题 时,首先,使用 ST 表计算出 中最小的一项 ,其下表为 .若 左边的元素数量更小,考虑枚举起点 ,假定终点为 ,则有方案数为:
想想如何去掉 .
当 时,就有:
由于 ,所以:
令:
则原式化简为:
只需要使用前缀和记录 ,就可以在 的时间里算出上式.
若 右边的元素数量更小,也是同理,考虑枚举终点为 ,假定起点为 ,则若令
原式化简为:
#include <bits/stdc++.h>#define int long longusing namespace std;#define querySum(l, r) (sum[(r)] - sum[(l) - 1])
const int N = 1e5 + 100;
int n, p, h[N], sum[N], ans;
struct Node { int n; int id; friend bool operator<(const Node a, const Node b) { return a.n < b.n; }} st[N][20];
Node query(int l, int r) { int len = log2(r - l + 1); return min(st[l][len], st[r - (1 << (len)) + 1][len]);}
int ceilDivided(int a, int b) { double da = 1.0 * a / b; int ia = a / b; if (da != (double)ia) { da++; } return da;}
void solve(int l, int r) { if (l > r) { // 不可能存在合法方案 return; } if (l == r) { // 仅一竖条 ans += max(0ll, h[l] - p + 1); return; } int m = query(l, r).id; int lim = h[m]; // 处理跨过中间的 if (m - l < r - m) { // 左边更少一点 for (int i = l; i <= m; i++) { int j0 = max(m, ceilDivided(p, lim) + i - 1); if (j0 <= r) ans += (lim + 1) * (r - j0 + 1) - querySum(j0 - i + 1, r - i + 1); } } else { // 右边更少一点 for (int j = m; j <= r; j++) { int i0 = min(m, j + 1 - ceilDivided(p, lim)); if (l <= i0) ans += (lim + 1) * (i0 - l + 1) - querySum(j - i0 + 1, j - l + 1); } } // 处理只在两边的 solve(l, m - 1); solve(m + 1, r);}
signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> p; // 预处理 ceil(p / i) for (int i = 1; i <= n; i++) { sum[i] = sum[i - 1] + ceilDivided(p, i); } for (int i = 1; i <= n; i++) { cin >> h[i]; } for (int i = 0; i <= n; i++) { st[i][0] = {h[i], i}; } for (int j = 1; j <= 17; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) { st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); } } solve(1, n); cout << ans << endl; return 0;}一般的,如果对于一道题,统计方案时有最大值或最小值作为阻碍/瓶颈,可以考虑分治。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


