洛谷 題解 P1083 【借教室】
阿新 • • 發佈:2018-11-02
0x00 先看資料範圍
$ 1≤n,m≤10^6 $,第一反應 \(O(nlogn)\)
0x01 5 pts
直接輸出 '0' 即可。
不要問我怎麼知道輸出 '0' 可以拿 5 pts。
保持微笑.jpeg *1
0x02 40~50 pts
考慮暴力。
按照題意列舉即可。
核心虛擬碼如下:
定義 n, m 為 int 型變數 定義 r 為 int 型陣列,大小為 Max_N 讀入 n, m 讀入 r 陣列 定義 d, s, t 為 int 型變數 使用變數 i 從 1 到 m 遍歷 讀入 d, s, t 使用變數 j 在 r 數組裡從 s 到 t 遍歷 r[j] 減去 d; 如果 r[j] < 0 那麼 輸出 "-1" 和回車 輸出 i 結束程式 否則 j 指標後移 輸出 "0" 結束程式
然後,考察你程式的常數的時候到了。
保持微笑.jpeg *2
0x03 70 pts
一看就是線段樹。
然而,眾所周知,線段樹的常數是比較大的,所以只有 70 pts。
當然,我也看見了用線段樹A題的大佬,在此表示由衷的敬意.
0x04 深入思考
回憶我們預測的時間複雜度:\(O(nlogn)\)
開始猜演算法
——阮行止
保持微笑.jpeg *3
然後想到二分答案
0x05 二分?
設:二分答案的內容為最多可以滿足第 mid 個人的需求
然後開始想 judge 函式。
這時候拼盡腦子想 \(O(n)\) 演算法
然後想到差分
0x06 二分 judge 函式之差分
虛擬碼:
函式引數:x(int 型整數) // 表示可否滿足第 x 個人的需求 Clear dif // dif 是大小為 Max_N 的 int 型陣列 For i (i between [1, x]) dif[s[i]] = dif[s[i]] + d[i] dif[t[i] + 1] = dif[t[i] + 1] - d[i] now = 0 For i (i between [1, n]) now += dif[i]; If now > r[i] Return false; Return true; }
0x07 二分
int l = 0, r = m, mid;
while (l < r) {
mid = (l + r + 1) >> 1;
if (judge(mid)) l = mid;
else r = mid - 1;
}
if (l == m) putchar('0');
else puts("-1"), write(l + 1);
幾點說明:
- 如果 judge(m) 為真,說明所有訂單均可滿足
- 因為 l 表示最多可以滿足第 l 個人的需求,所以第一個需要修改訂單的人的編號為 l + 1
0x08 程式碼
// luogu-judger-enable-o2
/**
* Problem: P1083 借教室.
* Author: 航空信奧.
* Date: 2018/08/23.
* Upload: Luogu.
*/
#include <stdio.h>
#include <string.h>
namespace HangKongXinAo {
template <typename _TpInt> inline _TpInt read();
template <typename _TpInt> inline void write(_TpInt x);
# define Max_N 1000007
int n, m, r[Max_N];
int d[Max_N], s[Max_N], t[Max_N];
int dif[Max_N];
bool judge(int x)
{
memset(dif, 0, sizeof(dif));
for (int i = 1; i <= x; i++) {
dif[s[i]] += d[i];
dif[t[i] + 1] -= d[i];
}
int now = 0;
for (int i = 1; i <= n; i++) {
now += dif[i];
if (now > r[i]) return false;
}
return true;
}
void Binary_search()
{
int l = 0, r = m, mid;
while (l < r) {
mid = (l + r + 1) >> 1;
if (judge(mid)) l = mid;
else r = mid - 1;
}
if (l == m) putchar('0');
else puts("-1"), write(l + 1);
}
int main()
{
n = read<int>();
m = read<int>();
for (int i = 1; i <= n; i++) {
r[i] = read<int>();
}
for (int i = 1; i <= m; i++) {
d[i] = read<int>();
s[i] = read<int>();
t[i] = read<int>();
}
Binary_search();
return 0;
}
char BufferRead[1 << 17];
int rLen = 0, rPos = 0;
inline char Getchar()
{
if (rPos == rLen) rPos = 0, rLen = fread(BufferRead, 1, 1 << 17, stdin);
if (rPos == rLen) return EOF;
return BufferRead[rPos++];
}
template <typename _TpInt>
inline _TpInt read()
{
register int flag = 1;
register char c = Getchar();
while ((c > '9' || c < '0') && c != '-')
c = Getchar();
if (c == '-') flag = -1, c = Getchar();
register _TpInt init = (c & 15);
while ((c = Getchar()) <= '9' && c >= '0')
init = (init << 3) + (init << 1) + (c & 15);
return init * flag;
}
template <typename _TpInt>
inline void write(_TpInt x)
{
if (x < 0) {
putchar('-');
write<_TpInt>(~x + 1);
}
else {
if (x > 9) write<_TpInt>(x / 10);
putchar(x % 10 + '0');
}
}
}
int main()
{
HangKongXinAo::main();
return 0;
}