diff --git a/TangDou/Topic/前缀和和差分洛谷题单总结.md b/TangDou/Topic/前缀和和差分洛谷题单总结.md index b5165bd..5d42dbe 100644 --- a/TangDou/Topic/前缀和和差分洛谷题单总结.md +++ b/TangDou/Topic/前缀和和差分洛谷题单总结.md @@ -134,6 +134,49 @@ int main() { 对于为什么可以二分:如果一个人无法被满足,则他后面的人全都不能被满足;如果一个人可以被满足,则他前面的人都可以被满足,这恰恰吻合了我们二分的性质。 +```cpp {.line-numbers} +#include +using namespace std; +const int N = 1000010; +#define int long long +#define endl "\n" +int n, m; // 天数和订单的数量 +int r[N]; // 第i天学校有r[i]个教室可借用 +int d[N], s[N], t[N]; // 借的教室数目、从第s天借到t天 +int b[N]; // 差分数组 +bool check(int x) { // 判断能不能通过x个人 + memset(b, 0, sizeof b); // 每次判断都要先初始化差分数组 + int sum = 0; // 记录需要借的教室数 + for (int i = 1; i <= x; i++) { + b[s[i]] += d[i]; // 因为只会对在s~l之间要借用教室的人产生影响,所以可以差分 + b[t[i] + 1] -= d[i]; // 差分,注意:是t[i]+1,因为要包含t[i]这个点 + } + for (int i = 1; i <= n; i++) { + sum += b[i]; // 因为cf是差分数组,所以sum就是在第i天的借教室的总数 + if (sum > r[i]) return false; // 不可行,如果要借的教室多于空的教室 + } + return true; // 可行 +} +signed main() { + cin >> n >> m; + for (int i = 1; i <= n; i++) cin >> r[i]; + for (int i = 1; i <= m; i++) cin >> d[i] >> s[i] >> t[i]; + if (check(m)) { // 如果全部满足 + cout << 0 << endl; // 输出0 + exit(0); // 直接结束程序 + } + int l = 1, r = m; // 二分左右区间 + while (l < r) { + int mid = l + r >> 1; + if (check(mid)) // 如果可行 + l = mid + 1; // 增多满足人数 + else // 否则 + r = mid; // 减少满足人数 + } + cout << "-1" << endl + << l; // 输出-1和需要修改的人 +} +``` ### [$P3406$ 海底高铁](https://www.luogu.com.cn/problem/P3406) ![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170857701.png)