zoukankan      html  css  js  c++  java
  • 【题解】JOISC2017 手持ち花火(Sparklers) | 20211106 模拟赛 你还没有导光吗(light)【二分 贪心】

    题目链接

    题目链接

    题意

    数轴上有 (n) 个人,每人手持一根烟花棒,一根烟花棒只能被点燃一次,燃烧 (t) 秒。初始第 (k) 个人手上的烟花棒刚刚点燃,随后所有人开始移动;当两人位置重叠且其中一个人的烟花棒还在燃烧时,一个人可以用自己的烟花棒点燃另一个的,耗时不计。现在希望每个人的烟花棒都被点燃过,问全程所有人最大速度的最小值。(nleq 10^5)

    题解

    首先二分。我们注意到以下性质:

    • 一个人其实可以一直全速奔跑;
    • 如果有两人同时有燃着的烟花棒,其实可以让一个人在烟花棒燃尽时再点燃另一个的,因此同一时间只有一个烟花棒被点燃;
    • 所有人都往烟花棒所在位置跑,大部分人的相对位置不变。

    因此我们需要做若干次决策,形如当前烟花棒燃着的人(或者说与他位置重叠的一群人)往左跑还是往右跑,一次决策会让烟花燃烧的剩余时间减一定值再加 (t)

    把往左往右的决策放入两个队列,每次我们会把队首尽可能短但总收益为正的一段合并起来,在左右之间任选一个可行的这样的段。如果这样的段清空不了则不合法。还有些元素没有被合并到段里,我们倒着做这个过程(即先算出结束时烟花棒的剩余时间,再把整个过程逆序做一遍)。

    #include<bits/stdc++.h>
    using namespace std;
    vector<int>vl,vr;
    int n,k,t;
    double len;
    pair<vector<pair<double,double>>,vector<pair<double,double>>> split(vector<int>v,double x){
    	vector<pair<double,double>>vl;
    	double co=0,get=0;
    	int u=-1;
    	for(int i=0;i<v.size();i++){
    		get-=v[i]/x/2;
    		co=max(co,-get);
    		get+=t;
    		if(get>=0){
    			vl.emplace_back(co,get);
    			u=i;
    			co=0;get=0;
    		}
    	}
    	co=0;get=0;
    	vector<pair<double,double>>vr;
    	int uu=v.size();
    	for(int i=v.size()-1;i>u;--i){
    		get-=t;
    		co=max(co,-get);
    		get+=v[i]/x/2;
    		if(get>=0){
    			vr.emplace_back(co,get);
    			uu=i;
    			co=0;get=0;
    		}
    	}
    	if(uu!=u+1)return {{{1e9,0}},{{1e9,0}}};
    	return make_pair(vl,vr);
    }
    bool check(vector<pair<double,double>>v1,vector<pair<double,double>>v2,double t0){
    	double cur=t0;
    	int u=0,v=0;
    	while(u<v1.size()||v<v2.size()){
    		if(u<v1.size()&&cur>=v1[u].first)cur+=v1[u++].second;
    		else if(v<v2.size()&&cur>=v2[v].first)cur+=v2[v++].second;
    		else return false;
    	}
    	return true;
    }
    bool check(double x){
    	auto vll=split(vl,x);
    	auto vrr=split(vr,x);
    	return check(vll.first,vrr.first,t)&&check(vll.second,vrr.second,t*1.*n-len/x/2);
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0);
    	cin>>n>>k>>t;
    	int lst=0;cin>>lst;
    	for(int i=1;i<k;i++){
    		int x;cin>>x;
    		vl.push_back(x-lst);
    		lst=x;
    	}
    	for(int i=k;i<n;i++){
    		int x;cin>>x;
    		vr.push_back(x-lst);
    		lst=x;
    	}
    	len=lst;
    	if(lst==0)return cout<<0,0;
    	reverse(vl.begin(),vl.end());
    
    	int l=0,r=1e9,ans=0;
    	while(l<=r){
    		int mid=(l+r)/2;
    		if(check(mid))r=mid-1,ans=mid;
    		else l=mid+1;
    	}
    	cout<<ans<<endl;
    }
    
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    eclipse快速给表达式生成对应变量的快捷键
    java截取字符串中的最后几个字符
    javascript删除数组元素的7个方法
    java构建树形列表(带children属性)
    elementui树表修改子节点不能实时更新的解决办法
    css3的user-select属性设置文本内容能否被选择
    javascript中for-in和for-of的区别
    计算机等级考试改革
    SQL分组查询
    Windows 8 快捷键
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/15518160.html
Copyright © 2011-2022 走看看