LOJ2392 JOISC2017 烟花棒 二分、贪心
先二分一个最大速度\(v\)。
分析移动的性质。很显然的事情是在火焰两边的所有人都会往火焰的方向以最快的速度运动,这样可以使当前位置更早获得火焰,同时当前拥有火焰的若干个人为了传递火焰自然也会以最快的速度移动。
接下来考虑某个没有火的人碰上了有火的人之后决策如何。假设有火的人\(A\)碰上了无火的人\(B\),如果\(A,B\)接下来要去的方向是一致的,那么肯定一起走直到\(A\)灭了再点燃\(B\);否则可以发现在碰上的瞬间点火和先\(AB\)一起走直到\(A\)无火时给\(B\)点火,这两种方案\(B\)能够点到火对应的相对距离范围是一致的。
所以我们可以认为\(AB\)相遇则一定会在一起跑,相当于给火焰增加了\(Tsec\)的燃烧时间,也就是说在任何时刻只会有最多一个位置有火。
那么我们实际需要做的决策就是在两个方向中选择一个方向让火往这边跑,将第一个相遇的位置加入火焰,再去做决策。不难发现在上述论述下,火焰向一边跑了之后到另一边所有人的相对距离不变,所以对于每一个人,如果火焰下一次选择它,那么消耗的时间是固定的,能够获得的时间也是固定的。我们把这两个值称为其权值,记为\((a_i,b_i)\)。
接下来的决策过程:从火焰的左边和右边找到第一个位置满足当火焰和这个位置相遇时时间相比开始增加。如果火焰可以往其中一个方向走到达这样的位置那么就走然后继续这个过程,否则肯定无解。
接下来到了走两边都一定让时间减少的部分,这里不能直接选择减的最少的位置走,因为这样的走法可能会影响决策集合从而导致无解。考虑一个常见的贪心Trick:我们已知过程结束时火焰的时间,那么我们倒着考虑,相当于把火焰左右的两个部分分别\(reverse\),\((a_i,b_i)\)交换然后做上述过程。这样不难证明从火焰左边的任何位置到最左端的位置一定能够获得正时间,右边同理。这样我们就可以通过这个问题是否有解得到整个问题是否有解了。
关于最后的Trick可以参考BZOJ3709
#include<bits/stdc++.h>
using namespace std;
int read(){
int a = 0; char c = getchar(); while(!isdigit(c)) c = getchar();
while(isdigit(c)){a = a * 10 + c - 48; c = getchar();} return a;
}
#define int long long
#define eps 1e-10
#define PII pair < int , int >
const int _ = 1e5 + 7;
int X[_] , N , K , T;
bool check(int sum , vector < PII > &A , vector < PII > &B){
int pos1 = 0 , pos2 = 0; if(sum < 0) return 0;
while(pos1 < A.size() || pos2 < B.size())
if(pos1 < A.size() && sum + A[pos1].first >= 0) sum += A[pos1++].second;
else if(pos2 < B.size() && sum + B[pos2].first >= 0) sum += B[pos2++].second;
else return 0;
return 1;
}
#define dis(a , b) ((X[a] - X[b]) / 2)
bool check1(int l1 , int r1 , int mid){
vector < PII > P , Q; int l = 0 , r = N + 1;
while(l < l1){
int pl = l , mn = 1e18;
while(pl != l1){
++pl; mn = min(mn , dis(pl , l + 1) - (pl - l) * T * mid);
if(dis(pl + 1 , l + 1) - (pl - l) * T * mid >= 0) break;
}
P.push_back(PII(mn , dis(pl + 1 , l + 1) - (pl - l) * T * mid)); l = pl;
}
while(r > r1){
int pr = r , mn = 1e18;
while(pr != r1){
--pr; mn = min(mn , dis(r - 1 , pr) - (r - pr) * T * mid);
if(dis(r - 1 , pr - 1) - (r - pr) * T * mid >= 0) break;
}
Q.push_back(PII(mn , dis(r - 1 , pr - 1) - (r - pr) * T * mid)); r = pr;
}
return check(T * mid * N - dis(N , 1) , P , Q);
}
bool check(int mid){
int l = K , r = K; vector < PII > P , Q;
while(l != 1){
int pl = l , mn = 1e18;
while(pl != 1){
mn = min(mn , (l - pl) * T * mid - dis(l , pl - 1));
--pl; if(dis(l , pl) <= (l - pl) * T * mid) break;
}
if(dis(l , pl) <= (l - pl) * T * mid) P.push_back(PII(mn , (l - pl) * T * mid - dis(l , pl)));
else break;
l = pl;
}
while(r != N){
int pr = r , mn = 1e18;
while(pr != N){
mn = min(mn , (pr - r) * T * mid - dis(pr + 1 , r));
++pr; if(dis(pr , r) <= (pr - r) * T * mid) break;
}
if(dis(pr , r) <= (pr - r) * T * mid) Q.push_back(PII(mn , (pr - r) * T * mid - dis(pr , r)));
else break;
r = pr;
}
return check(T * mid , P , Q) && check1(l - 1 , r + 1 , mid);
}
signed main(){
N = read(); K = read(); T = read() * 2; for(int i = 1 ; i <= N ; ++i) X[i] = read() * 2;
int L = 0 , R = 2e9 / T + 1;
while(L < R){
int mid = (L + R) >> 1;
check(mid) ? R = mid : L = mid + 1;
} cout << L; return 0;
}
LOJ2392 JOISC2017 烟花棒 二分、贪心的更多相关文章
- JOISC 2017 Day1 T3 烟花棒
JOISC 2017 Day1 T3 烟花棒 题意: 数轴上有\(N\)人在放烟花,一开始只有第\(K\)个人的烟花是点燃的,烟花燃烧的时间为\(T\)秒,求让所有人的烟花都可以点燃的速度的最小值 ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
- 2016-2017 ACM-ICPC CHINA-Final Ice Cream Tower 二分+贪心
/** 题目:2016-2017 ACM-ICPC CHINA-Final Ice Cream Tower 链接:http://codeforces.com/gym/101194 题意:给n个木块,堆 ...
- 【bzoj2097】[Usaco2010 Dec]Exercise 奶牛健美操 二分+贪心
题目描述 Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径. ...
- Codeforces_732D_(二分贪心)
D. Exams time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...
- CF732D Exams 二分 贪心
思路:二分+贪心 提交次数:10次以上 错因:刚开始以为二分(边界,$+1or-1$)写错了,调了半天,后来才发现是$ck()$写错了.开始只判了最后是否小于零,而应该中间一旦小于零就$return\ ...
- $CF949D\ Curfew$ 二分/贪心
正解:二分/贪心 解题报告: 传送门$QwQ$ 首先这里是二分还是蛮显然的?考虑二分那个最大值,然后先保证一个老师是合法的再看另一个老师那里是否合法就成$QwQ$. 发现不太会搞这个合不合法的所以咕了 ...
- $bzoj2067\ szn$ 二分+贪心
正解:二分+贪心 解题报告: 传送门$QwQ$ 题目大意就说有一棵树,然后要用若干条线覆盖所有边且不能重叠.问最少要用几条线,在用线最少的前提下最长的线最短是多长. 昂首先最少用多少条线这个还是蛮$e ...
- leetcode1552题解【二分+贪心】
leetcode1552.两球之间的磁力 题目链接 算法 二分+贪心 时间复杂度O(nlogn + nlogm) 1.根据题意描述,我们需要将m个球放入到n个篮子中,根据题目中数据范围描述发现m &l ...
随机推荐
- proxychains4配置使用
一丶安装 sudo apt-get install proxychains4 二丶修改配置文件 sudo vim /etc/proxychains.conf 在文本最后加上你的代理服务器地址,如果有用 ...
- 【转】LockSupport深入浅出
原文:https://www.cnblogs.com/qingquanzi/p/8228422.html 本篇是<自己动手写把"锁">系列技术铺垫的最后一个知识点.本篇 ...
- Linux自有服务(2)-Linux从入门到精通第六天(非原创)
文章大纲 一.设置主机名二.chkconfig三.ntp服务四.防火墙服务五.rpm管理(重点)六.cron/crontab计划任务(重点)七.学习资料下载八.参考文章 自有服务,即不需要用户独立 ...
- ssh免密登录(公钥私钥)指令
1.在.ssh目录中执行ssh-keygen -t rsa命令生成两个秘钥,公钥(id_rsa.pub)和私钥(id_rsa) 2.ssh-copy-id -i id_rsa.pub 对方用户名@对方 ...
- Python:日常应用汇总
判断路径中是否包含中文 import re def IsContainChinese(path:str) -> bool : cnPatter=re.compile(u'[\u4e00-\u9f ...
- json序列化时间日期数据注意
通过json序列化时间日期格式数据的时候需要注意,不能直接序列化,我写了一个类,可以借用 import json from datetime import datetime,date a = {'na ...
- limits the number of elements in an IN predicate to 2100 entries.
org.hibernate.engine.jdbc.spi.SqlExceptionHelper 131 - [TxId : f68db5f5b-qmgnc^1561639897640^271530 ...
- Generating YouTube-like IDs in Postgres using PL/V8 and Hashids
转自:https://blog.abevoelker.com/2017-01-03/generating-youtube-like-ids-in-postgres-using-plv8-and-has ...
- C#中的Queue集合
Queue<T>集合 特点:先进先出,简单来说,就是新添加的元素是顺序添加在集合尾部,但是,移除的时候是从顶部开始移除元素. 三个方法: Enqueue(T obj);//顺序添加一个值到 ...
- 通过不断迭代,编写<通过中缀表达式,构造表达式树>的代码
今天要练习的算法是通过中缀表达式生成表达式树.中缀.前缀.后缀表达式的概念就不赘述了,学习链接:中缀.前缀.后缀表达式. 参考代码学习链接:表达式树—中缀表达式转换成后缀表达式(一). [迭代 ①]: ...