Cod sursa(job #3350063)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 5 aprilie 2026 10:42:22
Problema Lupul Urias si Rau Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.7 kb
#include <iostream>
#include <fstream>
#include <cassert>

#include <algorithm>
#include <vector>

#include <random>

template<class T> using vec = std::vector<T>;
using ll = long long;

constexpr ll INF = 1e18;

ll ceil( ll a, ll b ) {
  if( a <= 0 ) return a / b;
  return (a - 1) / b + 1;
}

struct Line {
  ll ct, slope;
  Line(): ct(0), slope(0) {}
  Line( ll ct, ll slope ): ct(ct), slope(slope) {}
  ll operator ()( ll x ) const { return ct + x * slope; }
  ll overtake( const Line& that ) const {
    if( slope == that.slope ) return +INF;
    // ct + x * slope >= that.ct + x * that.slope
    // x * (slope - that.slope) >= (that.ct - ct)

    ll ret = ceil( that.ct - ct, slope - that.slope );
    // assert( (*this)(ret) >= that(ret) );
    // assert( (*this)(ret - 1) < that(ret - 1) );

    return ret;
  }
};

struct KinTour {
  struct Node {
    Line L;
    ll overtake;
  };

  vec<Node> aint;
  int aintn;
  ll t;
  KinTour( int n ): t(0) {
    aintn = 1;
    while( aintn < n ) aintn <<= 1;
    aint.assign( 2 * aintn, Node{ Line(0, 0), +INF } );
  }

  void pull( int idx ) {
    int left = idx * 2 + 1, right = idx * 2 + 2;
    if( aint[left].L.ct < aint[right].L.ct )
      std::swap( left, right );
    if( aint[left].L.slope < aint[right].L.slope )
      std::swap( left, right );

    ll overtake = aint[left].L.overtake( aint[right].L );

    if( overtake <= t ){
      aint[idx].L = aint[left].L;
      aint[idx].overtake = std::min( aint[left].overtake, aint[right].overtake );
    }else{
      aint[idx].L = aint[right].L;
      aint[idx].overtake = std::min({ overtake, aint[left].overtake, aint[right].overtake });
    }
  }

  void update( int idx, const Line &L ) {
    idx += aintn - 1;
    aint[idx].L = L;
    while( idx )
      pull( idx = (idx - 1) >> 1 );
  }

  ll query( ll new_t ) {
    t = new_t;
    while( aint[0].overtake <= t ){
      int u = 0;
      while( (aint[u * 2 + 1].overtake <= t || aint[u * 2 + 2].overtake <= t) ){
        if( aint[u * 2 + 1].overtake <= t ) u = u * 2 + 1;
        else u = u * 2 + 2;
      }

      pull( u );
      while( u )
        pull( u = (u - 1) >> 1 );
    }

    return aint[0].L(t);
  }
};

int main() {
  std::ifstream fin("euro.in");
  std::ofstream fout("euro.out");

  int n, fee;
  fin >> n >> fee;

  vec<int> costs(n);
  for( int &x : costs ) fin >> x;
  
  vec<ll> sp(n + 1, 0);
  for( int i = 0; i < n; i++ )
    sp[i + 1] = sp[i] + costs[i];

  // dp[i] = -fee + max{ dp[j] + (sp[i] - sp[j]) * i }
  // dp[i] = -fee + sp[i] * i + max{ (dp[j]) + i * (-sp[j]) }

  KinTour zile(n + 1);
  ll ret = 0;
  for( int i = 1; i <= n; i++ ){
    ret = sp[i] * (ll)i + zile.query( i ) - fee;
    zile.update( i, Line(ret, -sp[i]) );
  }

  fout << ret << std::endl;
  return 0;
}