zoukankan      html  css  js  c++  java
  • CF1137 Train Car Selection

    题意

    给定一个数列,初始有(n)(0)
    (m)个操作,为以下三种:

    1. 在最前面插入(k)(0)
    2. 在最后面插入(k)(0)
    3. 对于第(i)个数,加上(k(i-1)+b)

    每次操作完毕后,输出数列中的最小值,以及第一次出现的位置。

    (n leq 10^9,m leq 3 imes 10^5)

    传送门

    思路

    对于一段(0),其实真正有用的只有第一个,只要记录第一个的位置就好。

    首先对于第一个操作,因为只有加法,显然第一个(0)肯定是最小的,我们可以把之前的所有都忽略。

    然后就变成了加某个一次函数,求最小值。

    考虑数列中能成为最小值的数,这个非常(对我来说 bushi)套路,把位置当做横坐标,值当做纵坐标,在下凸壳上的点才有可能成为最小值。

    那么我们用栈维护下凸壳即可。

    全局的加法可以维护两个全局变量实现,新加的点减掉前面的影响即可。

    #include <bits/stdc++.h>
    typedef long long ll;
    long long n,k,b;
    int Q,opt,x,y,tp;
    struct point{
    	ll x,y;
    }st[300005];
    inline point operator -(point x,point y){
    	return point{x.x-y.x,x.y-y.y};
    }
    ll cal(point x){ return x.y+b+(x.x-1)*k; }
    ll cross(point x,point y){ return x.x*y.y-x.y*y.x; } 
    int main(){
    	scanf("%lld%d",&n,&Q);
    	st[++tp]={1,0};
    	while (Q--){
    		scanf("%d",&opt);
    		if (opt==1){
    			scanf("%d",&x);
    			st[tp=1]={1,0};
    			k=0,b=0,n+=x;
    		}else if (opt==2){
    			scanf("%d",&x);
    			point t={n+1,-cal(point{n+1,0})};
    			n+=x;
    			if (cal(st[tp])>0){
    				while (tp>=2 && cross(st[tp-1]-t,st[tp]-t)<=0) tp--;
    				st[++tp]=t;
    			}	
    		}else{
    			scanf("%d%d",&y,&x);
    			k+=x,b+=y;
    			while (tp>=2 && cal(st[tp])>=cal(st[tp-1])) tp--;
    		}
    		printf("%lld %lld
    ",st[tp].x,cal(st[tp]));
    	}
    } 
    

    后记

    鸽子更博了,在家都变懒了,不想开学了

  • 相关阅读:
    陶瓷电容的结构、工艺、失效模式
    Vue.js最佳实践
    Vue 超快速学习
    CSS 小技巧
    HTML5 Canvas
    webkit下面的CSS设置滚动条
    Some untracked working tree files would be overwritten by checkout. Please move or remove them before you can checkout. View them
    JSCS: Please specify path to 'JSCS' package
    React中ref的使用方法
    React 60S倒计时
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/12498719.html
Copyright © 2011-2022 走看看