题意:有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. 一份关于.NET Core云原生采用情况调查

    调查背景 Kubernetes 越来越多地在生产环境中使用,围绕 Kubernetes 的整个生态系统在不断演进,新的工具和解决方案也在持续发布.云原生计算的发展驱动着各个企业转向遵循云原生原则(启动 ...

  2. 洛谷 P5150 题解

    题面 因为 n=lcm(a,b)n = lcm(a, b)n=lcm(a,b) ,可以得出: a  和 b  的质因数都是 n 的质因数 对于 n  的每个质因数 x ,在 n 中的次数为 y ,那么 ...

  3. EF Core的Code First 基础

    一.创建实体类与映射类 通过NuGet引用Microsoft.EntityFrameworkCore 1.创建实体类 Code First可以通过为实体类字段添加相应特性,来创建对应的字段类型等,举例 ...

  4. codeforces 327 A Ciel and Dancing

    题目链接 给你一串只有0和1的数字,然后对某一区间的数翻转1次(0变1 1变0),只翻转一次而且不能不翻转,然后让你计算最多可能出现多少个1. 这里要注意很多细节 比如全为1,要求必须翻转,这时候我们 ...

  5. jenkins弱口令漏洞

    jenkins弱口令漏洞 一.漏洞描述 通过暴力破解管理控制台,如果爆破成功,可获得后台管理权限.操作后台,后台可通过脚本命令行功能执行系统命令,如反弹shell等,低权限可以通过创建控制台输出方式执 ...

  6. Task CancellationTokenSource和Task.WhenAll的应用

    Task是.net4.0推出的异步编程类,与ThreadPool.QueneUserWorkItem方法类似的是,Task也是使用线程池来工作的.但Task比起这个QueneUserWorkItem的 ...

  7. 【算法】【查找】二分法 Bisection

    #include<stdio.h> int main(){ ,,,,,,,,,,,,,,}; ; //长度 ; //要查找到的值 int Bisection(int x,int* a,in ...

  8. 创建docker容器遇到的错误

    1.问题截图 2.问题描述 出现该问题就是docker版本和系统版本不兼容导致的. 现在的系统版本和docker的版本如下: 3.问题解决 安装低版本的docker或者高版本的系统(Centos7.4 ...

  9. 996工作制?不如花点时间学知识!北栀暗影教你如何用WordPress搭建专业网站

    很多70后.80后小时候都看过这样一部动画片-<半夜鸡叫>.讲的是地主"周扒皮"为了长工们能多干些活,半夜三更起来学鸡叫让长工劳动(卖身契上规定:鸡叫就得起床干活劳动) ...

  10. VMware安装Centos7虚拟机

    首先安装虚拟机很简单,所以呢,具体的安装过程就引用别人的博客,这篇文字很详细,引用之后会在后面加上一些遇到的问题: 原文:https://blog.csdn.net/babyxue/article/d ...