• 洛谷 题解 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;
    }
    
  • 相关阅读:
    数据结构、算法、及线性表总结
    第二次博客作业: 函数+进制转换器v1.0beta
    c语言文件
    Oracle中Left Outer Join和外关联(+)的区别
    Oracle中trunc函数、round 函数、ceil函数和floor 函数的使用
    Oracle 表之间的连接 JOIN
    Oracle TRUNCATE语法
    使用Content editor webpart 为NewForm增加默认值
    Metadata serviceTaxonomyHiddenList 权限
    SQL server总是不能远程连接
  • 原文地址:https://www.cnblogs.com/hkxadpall/p/9895949.html
Copyright © 2020-2023  润新知