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]));
    	}
    } 
    

    后记

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

  • 相关阅读:
    iOS 10适配知识点
    iOS中的【库】
    修改UISearchBar的Cancel按钮的颜色和文字
    UIScrollView 滑动手势与右滑返回冲突
    Sqoop使用手册
    Hbase常用操作CRUD(增删改查)
    HBase 常用Shell命令
    搭建HBase完全分布式集群
    Mac下安装HBase及详解
    使用brew安装软件
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/12498719.html
Copyright © 2011-2022 走看看