题意:有n个人,每个人有一件衣服需要洗,可以自己手洗花费t时间,也可以用洗衣机洗,但是洗衣机只有一台,即每个时刻最多只能有·一个人用洗衣机洗衣服。现在给你每个人最早可以开始洗衣服的时间,问当洗衣机的洗衣时间分别为1, 2....t的时候洗完所有衣服的最短时间。

思路:首先容易想到我们先把所有人按照洗衣服的时间排序。我们发现,最终洗衣服时间的瓶颈肯定在于后面的人,所以我们考虑怎么使用洗衣机使得总的洗衣时间最短。首先最后一个人是一定要用洗衣机洗衣服的,因为洗衣机的洗衣服时间 <= t, 那么最后一个人用洗衣机洗衣服不会让总时间变长,只可能变短。同理,如果最后一个人用洗衣机和倒数第二个人不冲突的话,倒数第二个人肯定也用洗衣机了。如果倒数第二个人用不了洗衣机,那么前面的人也没必要用洗衣机了,因为倒数第二个人的洗衣时间肯定大于等于前面的人,最后时间的瓶颈只可能在倒数第二个人身上或者倒数第一个人身上了。以此类推,我们可以发现。最后用洗衣机的人的序列肯定是原序列的一个后缀。那么,对于当前的x,怎么确定哪些人用洗衣机呢?设b[i]为第i个人开始洗衣服的时间,假设是从第i个人开始用洗衣机洗衣服,时间限制可能是两种:1:来自第i - 1个人手洗的时间限制:b[i - 1] + t。2:后面的人用洗衣机的时间的结束时间。这个结束时间怎么算呢?我们假设从第i个人开始用洗衣机,最理想情况是他一用完洗衣机别人就可以用,那么时间是b[i] + (n - i + 1) * x, 我们把i及其以后的所有人的理想状态时间都算出来,取最大值就是实际的结束时间。那么我们发现从i开始的人用洗衣机的时间是max(b[i - 1] + t, max(b[k] + (n - k + 1) * x)) (k >= i)。容易发现,b[k] + t是个单调递增的函数, max(b[k] + (n - k + 1) * x)是个单调递减的函数,他们俩取max是一个单谷函数,最优解就是谷底。这个好像不是严格单调函数不能三分,只能暴力枚举。那么对于一个特定的x时间复杂度是O(n)的。但是现在有n个x,怎么办?我们发现,当x等于t的时候,谷底一定在最后面,随着x的不断变小,谷底会逐渐往前移动,那么我们可以用一个指针来指向谷底,每当x减一的时候判断一下谷底是不是前移了,如果是就往前移动。那么新的问题出现了,b[i - 1] + t是常数不用维护,x减一之后max(b[k] + (n - k + 1) * x))好像得全部重新计算了?如果把n - k + 1看成斜率,b[k]看成截距,那么问题就转化为了在一堆直线中当横坐标确定时找纵坐标的最大值,这个用李超线段树可以在O(log(n))的时间内做到。

代码:

#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define ls (o << 1)
#define rs (o << 1 | 1)
using namespace std;
const int maxn = 1000010;
struct line {
double k, b;
};
line a[maxn];
int tot;
struct node {
int id;
};
node tr[maxn * 4];
double get_pos(int x, int y) {
return a[x].k * y + a[x].b;
}
double cross(int x, int y) {
return (a[x].b - a[y].b) / (a[y].k - a[x].k);
}
void init(int o, int l, int r) {
tr[o].id = 0;
if(l == r) return;
int mid = (l + r) >> 1;
init(ls, l, mid);
init(rs, mid + 1, r);
}
void update(int o, int l, int r, int now) {
if(!tr[o].id) {
tr[o].id = now;
return;
}
int x = tr[o].id;
double l1 = get_pos(now, l), r1 = get_pos(now, r);
double l2 = get_pos(x, l), r2 = get_pos(x, r);
if(l1 <= l2 && r1 <= r2) {
return;
}
else if(l1 > l2 && r1 > r2) {
tr[o].id = now;
return;
}
int mid = (l + r) >> 1;
double y = cross(now, x);
if(y <= mid) update(ls, l, mid, r1 > r2 ? x : now);
else update(rs, mid + 1, r, l1 > l2 ? x : now);
if((y <= mid && r1 > r2) || (y > mid && l1 > l2))
tr[o].id = now;
}
int query(int o, int l, int r, int pos) {
if(l == r) {
return tr[o].id;
}
int mid = (l + r) >> 1, ans = 0;
if(pos <= mid) ans = query(ls, l, mid, pos);
else ans = query(rs, mid + 1, r, pos);
if(!tr[o].id) return ans;
int x = tr[o].id;
if(get_pos(x, pos) > get_pos(ans, pos)) return x;
else return ans;
}
int b[maxn];
LL res[maxn];
int main() {
int n;
LL t;
while(~scanf("%d%lld", &n, &t)) {
init(1, 1, t);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
sort(b + 1, b + 1 + n);
for (int i = 1; i <= n; i++) {
a[i] = (line){(double)n - i + 1, (double)b[i]};
}
b[0] = -t;
LL tmp, tmp1;
update(1, 1, t, n);
int p = n - 1;
for (int i = t; i >= 1; i--) {
while(1) {
int ans = query(1, 1, t, i);
LL t1 = b[ans] + ((LL)n - ans + 1) * i;
tmp = max(t1, b[p] + t);
if(p == 0) break;
tmp1 = max(max(t1, b[p] + ((LL) n - p + 1) * i), b[p - 1] + t);
if(tmp1 <= tmp) {
update(1, 1, t, p);
p--;
}
else break;
}
res[i] = tmp;
}
for (int i = 1; i < t; i++) {
printf("%lld ", res[i]);
}
printf("%lld\n", res[t]);
}
}

  

2019 ICPC南京网络预选赛 I Washing clothes 李超线段树的更多相关文章

  1. 南京网络赛G-Lpl and Energy【线段树】

    During tea-drinking, princess, amongst other things, asked why has such a good-natured and cute Drag ...

  2. 2019 ICPC南京网络赛 F题 Greedy Sequence(贪心+递推)

    计蒜客题目链接:https://nanti.jisuanke.com/t/41303 题目:给你一个序列a,你可以从其中选取元素,构建n个串,每个串的长度为n,构造的si串要满足以下条件, 1. si ...

  3. 2019 ICPC 南京网络赛 F Greedy Sequence

    You're given a permutation aa of length nn (1 \le n \le 10^51≤n≤105). For each i \in [1,n]i∈[1,n], c ...

  4. 2019 ICPC 南京网络赛 H-Holy Grail

    As the current heir of a wizarding family with a long history,unfortunately, you find yourself force ...

  5. 2019南昌邀请赛网络预选赛 M. Subsequence

    传送门 题意: 给出一个只包含小写字母的串 s 和n 个串t,判断t[i]是否为串 s 的子序列: 如果是,输出"YES",反之,输出"NO": 坑点: 二分一 ...

  6. 2019 ICPC 南昌网络赛

    2019 ICPC 南昌网络赛 比赛时间:2019.9.8 比赛链接:The 2019 Asia Nanchang First Round Online Programming Contest 总结 ...

  7. ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)

    Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...

  8. 2019 ICPC南京站网络赛 H题 Holy Grail(BF算法最短路)

    计蒜客题目链接:https://nanti.jisuanke.com/t/41305 给定的起点是S,终点是T,反向跑一下就可以了,注意判负环以及每次查询需要添加边 AC代码: #include< ...

  9. 2018ACM/ICPC 焦作网络预选赛-A Magic Mirror

    Jessie has a magic mirror. Every morning she will ask the mirror: 'Mirror mirror tell me, who is the ...

随机推荐

  1. vue.js主要内容

    vue的主要内容 1.了解vue 2.vue开发环境的搭建和脚手架工具的使用 3.vue具体的指令和项目实战 1.了解vue 1.具备基础:html.css.js,模块化概念.ES6语法(简单即可) ...

  2. python中对多态的理解

    目录 python中对多态的理解 一.多态 二.多态性 三.鸭子类型 python中对多态的理解 一.多态 多态是指一类事物有多种形态,比如动物类,可以有猫,狗,猪等等.(一个抽象类有多个子类,因而多 ...

  3. DesignPattern系列__01SingletonResponsibility

    单一职责原则 单一职责原则:一个类应该只有一个原因引起改变,即一个类应该只负责一个业务逻辑. 问题由来:类T负责t1, t2两个职责,当因为t1j对类T修改的时候,可能导致类T出现问题而影响职责t2. ...

  4. Github上fork的项目如何merge原Git项目

    问题场景 小明在Github上fork了一个大佬的项目,并clone到本地开发一段时间,再提交merge request到原Git项目,过了段时间,原作者联系小明,扔给他下面这幅截图并告知合并处理冲突 ...

  5. Linq查找最大值max最小值min效率比较

    对linq查找极值的几种方法做一个效率上的比较 // 首先创建了一个10_000_000大小的PointF列表 var rdn = new Random(); var points = Enumera ...

  6. 夯实Java基础(十一)——内部类

    1.内部类的概念 内部类顾名思义:将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.对于很多Java初学者来说,内部类学起来真的是一头雾水,根本理解不清楚是个什么东西,包括我自己(我太菜 ...

  7. Docker系列开篇之Virtual Machine VS Container(一)

    前言 本节开始我们正式进入Docker系列,网上关于Docker相关文章如数家珍,写博客至今,我也一直在朝着如何写出通俗易懂且不枯燥的文章这个目标前进,喃喃自语的同时也希望看到文章的童鞋能明白我在讲什 ...

  8. c#图片的平移与旋转

    1新建文件夹,添加一个图片 2 添加控件 两个button控件 一个image控件 一个Canvas控件 3 代码实现 using System;using System.Collections.Ge ...

  9. Educational Codeforces Round 70 (Rated for Div. 2)

    这次真的好难...... 我这个绿名蒟蒻真的要崩溃了555... 我第二题就不会写...... 暴力搜索MLE得飞起. 好像用到最短路?然而我并没有学过,看来这个知识点又要学. 后面的题目赛中都没看, ...

  10. Tomcat源码分析 (二)----- Tomcat整体架构及组件

    前言 Tomcat的前身为Catalina,而Catalina又是一个轻量级的Servlet容器.在美国,catalina是一个很美的小岛.所以Tomcat作者的寓意可能是想把Tomcat设计成一个优 ...