zoukankan      html  css  js  c++  java
  • AT3949[AGC022D]Shopping【贪心】

    正题

    题目链接:https://www.luogu.com.cn/problem/AT3949


    题目大意

    长度为\(L\)的坐标轴上,给出\(n\)个点,每个点\(x_i\)需要购物\(t_i\)的时间,一辆车在\(0\sim L\)折返跑,求从\(0\)出发购物完回到\(0\)的最短时间。

    \(n\in[1,3\times 10^5],L\in[1,10^9]\),输入的\(x_i\)单调递增。


    解题思路

    挺奇妙的题目,\(WC2021\)讲课的题。

    首先每个\(t_i\)\(\%\)上一个\(2\times L\)。然后把那些\(2\times L\)加到答案里先,这些无可避免。

    然后考虑一个点,如果从右边进只需要到达一次端点就视为左括号,如果从右边进只需要到达一次端点就视为右括号。

    先默认每个点的贡献都是\(2\times L\),显然一个左括号和一个右括号匹配可以减少\(2\times L\)的贡献,因为如果先走右边那个再来走左边那个,这样他们的贡献和就是\(2\times L\)

    而有些点既可以视为左又可以视为右,此时我们需要最大化匹配数。

    其实还有一个性质,如果一个节点开始固定作为左括号,那么它后面的一定不会有固定作为右括号的(拿作为左右括号的条件看一下就能理解了)。所以不会有两个固定的括号匹配。

    然后就可以直接贪心匹配了,时间复杂度\(O(n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=3e5+10;
    int n,len,x[N],t[N],l[N],r[N],ans;
    int main()
    {
    	scanf("%d%d",&n,&len);
    	for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    	for(int i=1;i<=n;i++)scanf("%d",&t[i]);
    	for(int i=1;i<=n;i++){
    		ans+=t[i]/(2*len);t[i]%=2*len;
    		if(!t[i]){ans--;continue;}
    		l[i]=(t[i]<=x[i]*2);
    		r[i]=(t[i]<=(len-x[i])*2);
    	}
    	int lim=n,L=0,R=0;ans+=n+1-r[n];
     	for(int i=1;i<n;i++){
    		if(!l[i]&&!r[i])continue;
    		if(!r[i]){lim=i;break;}
    		if(!l[i]&&L)L--,ans--;
    		else if(l[i]) L++;
    	}
    	for(int i=n-1;i>=lim;i--){
    		if(!l[i]&&!r[i])continue;
    		if(!l[i])break;
    		if(!r[i]&&R)R--,ans--;
    		else if(r[i]) R++;
    	}
    	ans-=(L+R)>>1;
    	printf("%lld\n",2ll*ans*len);
    	return 0;
    }
    
  • 相关阅读:
    人性的经典总结54句
    系统程序员成长计划文本处理(XML解析器)
    系统程序员成长计划-像机器一样思考(二)
    Android输入事件流程
    系统程序员成长计划文本处理(INI解析器)
    request范围内共享属性 request_attribute.jsp
    系统程序员成长计划-像机器一样思考(三)
    系统程序员成长计划-像机器一样思考(一)
    Android IPC机制详解
    系统程序员成长计划文本处理(一)状态机(1)
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14396559.html
Copyright © 2011-2022 走看看