洛谷 题解 P1083 【借教室】

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);

几点说明:

  1. 如果 judge(m) 为真,说明所有订单均可满足
  2. 因为 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;
}
posted @ 2018-11-02 14:09  航空信奥  阅读(244)  评论(0编辑  收藏  举报