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 ...
随机推荐
- Fortify漏洞之Portability Flaw: File Separator 和 Poor Error Handling: Return Inside Finally
继续对Fortify的漏洞进行总结,本篇主要针对 Portability Flaw: File Separator 和 Poor Error Handling: Return Inside Fina ...
- 使用Hybris的customer coupon进行促销活动(promotion)
登录Backoffice,在Coupon菜单里创建一个新的类型为Customer Coupon的优惠券: 在菜单Marketing->Promotion Rules里,创建一条新的促销规则Pro ...
- 微信公众号 $GLOBALS['HTTP_RAW_POST_DATA']数据问题
公司的微信公众号最近出现问题,所有的功能都不能用,一开始以为是微信公众号验证的问题,经过排查才发现是$GLOBALS['HTTP_RAW_POST_DATA']这里的问题,微信公众号会把用户的一些操作 ...
- Nginx 高级配置-变量使用
Nginx 高级配置-变量使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用,变量可以分为内置变量和自定义变 ...
- db.sqlite如何导出转储为sql文件
在使用 django框架写博客时,用的是sqlite数据库,想要将其中的db.sqlite转储为sql文件, 我是在linux下使用的,很多linux系统下都自带sqlite 检查是否安装sqlite ...
- java国际化之时区问题处理
原文:https://moon-walker.iteye.com/blog/2396035 在国际化的项目中需要处理的日期时间问题主要有两点: 1.日期时间的国际化格式问题处理: 2.日期时间的时区问 ...
- AMD SATA Download (解决win10 磁盘占用100%问题)
需要下载的AMD SATA 驱动: 下载AMD SATA https://github.com/StoneIsDeveloper/UsefulTools/blob/master/AMD%20SATA/ ...
- 两数相加[链表加法] LeetCode.2
给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和 ...
- Windows平台部署 Asp.Net Core 3.1.0,将 ASP.NET Core 应用发布到 IIS ,使用 IIS 在 Windows 上托管 ASP.NET Core
第一部分:本教程介绍如何在 IIS 服务器上托管 ASP.NET Core 应用. 官方文档地址:https://docs.microsoft.com/zh-cn/aspnet/core/tutori ...
- AjAX 异步通信
<!DOCTYPE html> <html lang="en"> <head> <title>xmlhttprequest ajax ...