Problem:
B - Minimum Upper Sum
Time Limit: 3 sec
問題文
この問題はPython3でのACが確認されていないため、C++などの高速な言語の使用をおすすめします。
長さ$N$の数列$A = (A_1, A_2, \dots, A_N)$が与えられます。この数列を$K$個の連続する空でない区間に区切ります。形式的には、次の条件を満たす$K+1$個の自然数$1 = i_1 < i_2 < \dots < i_{K} < i_{K+1} = N+1$を選んで、$A$を$K$個の区間$[i_1, i_2), [i_2, i_3), \dots, [i_j, i_{j+1}), \dots, [i_{K}, i_{K+1})$に区切ります。
$j$番目の区間の長さを$l_j\,(=i_{j+1}-i_{j})$、この区間における$A$の最大値を$m_j$とします。
適切に区切り方を定めたとき、$\sum_{j=1}^K m_j l_j$の最小値を求めてください。
制約
$1 \leq N \leq 10^5$
$1 \leq K \leq \min(N, 20)$
$1 \leq A_i \leq 10^9$
入力はすべて整数
入力
$N\quad K$
$A_1\quad A_2 \quad \dots\quad A_N$
出力
答えを出力せよ。
入力例1
5
3
1
2
3
4
5
出力例1
17
例えば、$(1,2), (3), (4,5)$と分けると、求める値は$17$となり、これが最小となります。
入力例2
10
2
4
95
36
32
29
18
95
14
87
95
出力例2
859

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct sparse_table {
    vector<vector<ll>> v;
    vector<ll> a;
    ll n;

    sparse_table(ll n_, vector<ll> &b) {
        v.resize(__lg(n_) + 1, vector<ll>(n_));
        n = n_;
        a = b;
        build();
    }

    void build() {
        for (ll i = 0; i < n; i++) {
            v[0][i] = a[i];
        }
        for (ll j = 1; j <= __lg(n); j++) {
            for (ll i = 0; i + (1 << j) <= n; i++) {
                v[j][i] = max(v[j - 1][i], v[j - 1][i + (1 << (j - 1))]);
            }
        }
    }

    ll get(ll l, ll r) {
        ll j = __lg(r - l);
        return max(v[j][l], v[j][r - (1 << j)]);
    }
};

int main() {
    ll n, k;
    cin >> n >> k;
    vector<ll> a(n);
    for (ll i = 0; i < n; i++) {
        cin >> a[i];
    }
    sparse_table t(n, a);

    vector<vector<ll>> dp(k + 1, vector<ll>(n + 1, 1e18));
    dp[0][0] = 0;
    for (ll i = 1; i <= k; i++) {
        ll opt = 0;
        for (ll j = 1; j <= n; j++) {
            ll nw = 0;
            for (ll p = max(0ll, opt - 100); p <= min(j - 1, opt + 100); p++) {
                if (dp[i][j] > dp[i - 1][p] + (j - p) * t.get(p, j)) {
                    dp[i][j] = dp[i - 1][p] + (j - p) * t.get(p, j);
                    nw = p;
                }
            }
            for (ll p = max(0ll, j - 100); p <= j - 1; p++) {
                if (dp[i][j] > dp[i - 1][p] + (j - p) * t.get(p, j)) {
                    dp[i][j] = dp[i - 1][p] + (j - p) * t.get(p, j);
                    nw = p;
                }
            }
            opt = nw;
        }
    }

    cout << dp[k][n] << '\n';
}
accuracy: 0.2727272727272727
time_ms: 2890
memory_kb: 35316
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct sparse_table {
    vector<vector<ll>> v;
    vector<ll> a;
    ll n;

    sparse_table(ll n_, vector<ll> &b) {
        v.resize(__lg(n_) + 1, vector<ll>(n_));
        n = n_;
        a = b;
        build();
    }

    void build() {
        for (ll i = 0; i < n; i++) {
            v[0][i] = a[i];
        }
        for (ll j = 1; j <= __lg(n); j++) {
            for (ll i = 0; i + (1 << j) <= n; i++) {
                v[j][i] = max(v[j - 1][i], v[j - 1][i + (1 << (j - 1))]);
            }
        }
    }

    ll get(ll l, ll r) {
        ll j = __lg(r - l);
        return max(v[j][l], v[j][r - (1 << j)]);
    }
};

int main() {
    ll n, k;
    cin >> n >> k;
    vector<ll> a(n);
    for (ll i = 0; i < n; i++) {
        cin >> a[i];
    }
    sparse_table t(n, a);

    vector<vector<ll>> dp(k + 1, vector<ll>(n + 1, 1e18));
    dp[0][0] = 0;
    for (ll i = 1; i <= k; i++) {
        ll opt = 0;
        for (ll j = 1; j <= n; j++) {
            ll nw = 0;
            for (ll p = max(0ll, opt - 150); p <= min(j - 1, opt + 150); p++) {
                if (dp[i][j] > dp[i - 1][p] + (j - p) * t.get(p, j)) {
                    dp[i][j] = dp[i - 1][p] + (j - p) * t.get(p, j);
                    nw = p;
                }
            }
            opt = nw;
        }
    }

    cout << dp[k][n] << '\n';
}
accuracy: 0.2727272727272727
time_ms: 2880
memory_kb: 35248
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct sparse_table {
    vector<vector<ll>> v;
    vector<ll> a;
    ll n;

    sparse_table(ll n_, vector<ll> &b) {
        v.resize(__lg(n_) + 1, vector<ll>(n_));
        n = n_;
        a = b;
        build();
    }

    void build() {
        for (ll i = 0; i < n; i++) {
            v[0][i] = a[i];
        }
        for (ll j = 1; j <= __lg(n); j++) {
            for (ll i = 0; i + (1 << j) <= n; i++) {
                v[j][i] = max(v[j - 1][i], v[j - 1][i + (1 << (j - 1))]);
            }
        }
    }

    ll get(ll l, ll r) {
        ll j = __lg(r - l);
        return max(v[j][l], v[j][r - (1 << j)]);
    }
};

int main() {
    ll n, k;
    cin >> n >> k;
    vector<ll> a(n);
    for (ll i = 0; i < n; i++) {
        cin >> a[i];
    }
    sparse_table t(n, a);

    vector<vector<ll>> dp(k + 1, vector<ll>(n + 1, 1e18));
    dp[0][0] = 0;
    for (ll i = 1; i <= k; i++) {
        ll opt = 0;
        for (ll j = 1; j <= n; j++) {
            ll nw = 0;
            for (ll p = max(0ll, opt - 100); p <= min(j - 1, opt + 100); p++) {
                if (dp[i][j] > dp[i - 1][p] + (j - p) * t.get(p, j)) {
                    dp[i][j] = dp[i - 1][p] + (j - p) * t.get(p, j);
                    nw = p;
                }
            }
            opt = nw;
        }
    }

    cout << dp[k][n] << '\n';
}
accuracy: 0.2727272727272727
time_ms: 1930
memory_kb: 35360
final_rank: 17

code_snippet: // AOJ #3255 Minimum Upper Sum
// 2025.4.13

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1e18;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0; int c = gc();
	do n = 10 * n + (c & 0xf); while ((c = gc()) >= '0');
	return n;
}

void Cout(ll n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

vector<ll> A;
vector<vector<ll>> st;
int n;

void buildSparseTable() {
    int L = 32 - __builtin_clz(n);
    st.assign(n + 1, vector<ll>(L, 0));
    for (int i = 1; i <= n; i++) st[i][0] = A[i];
    for (int j = 1; (1 << j) <= n; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}

ll queryMax(int L, int R) {
    int len = R - L + 1;
    int p = 31 - __builtin_clz(len);
    return max(st[L][p], st[R - (1 << p) + 1][p]);
}

ll cost(int i, int j) { return (ll)(j - i + 1) * queryMax(i, j); }

int main(){
    n = Cin();
    int K = Cin();

    A.resize(n + 1);
    for (int i = 1; i <= n; i++) A[i] = Cin();

    buildSparseTable();
    vector<vector<ll>> dp(K + 1);
    dp[1].resize(n + 1);
    for (int i = 1; i <= n; i++) dp[1][i] = cost(i, n);

    for (int k = 2; k <= K; k++){
        int msize = n - k + 1;
        dp[k].resize(msize + 1, INF);

        function<void(int, int, int, int)> dc = [&](int L, int R, int optL, int optR) {
            if (L > R) return;
            int mid = (L + R) / 2;
            ll bestVal = INF;
            int bestIdx = -1;
            int start = max(mid, optL);
            int end = min(optR, msize);
            for (int j = start; j <= end; j++){
                ll cand = dp[k-1][j+1] + cost(mid, j);
                if (cand < bestVal) {
                    bestVal = cand;
                    bestIdx = j;
                }
            }
            dp[k][mid] = bestVal;
            dc(L, mid - 1, optL, bestIdx);
            dc(mid + 1, R, bestIdx, optR);
        };
        dc(1, msize, 1, msize);
    }
    Cout(dp[K][1]);
    return 0;
}
accuracy: 0.29545454545454547
time_ms: 150
memory_kb: 36024
final_rank: 16

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)
#define ALL(v) v.begin(),v.end()

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){/*
    cerr<<"query:"<<x<<endl;
    for(const auto&l:lines)debug(l);
    ll ress=val(0,x);
    REP(i,lines.size())ress=min(ress,val(i,x));
    cerr<<"res:"<<ress<<endl;*/
    int l=-1,r=lines.size()-1;
    ll res=min(val(0,x),val(r,x));
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x)){
        res=min(res,val(mid,x));
        r=mid;
      }
      else{
        res=min(res,val(mid+1,x));
        l=mid+1;
      }
    }
    //if(res!=ress)cerr<<"hogehogehogehoge"<<res<<endl;
    return res;
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,2*LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        vector<Line> vec,vec2;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)vec.push_back({a,b});
            else vec2.push_back({a,b});
          
          delete (it->second);
          it=B.erase(it);
        }

        sort(ALL(vec),[](const Line&a,const Line&b){return a.a>b.a;});
        for(const auto&[a,b]:vec)B[m]->push_back(a,b);
        sort(ALL(vec2),[](const Line&a,const Line&b){return a.a<b.a;});
        for(const auto&[a,b]:vec2)B[m]->push_front(a,b);

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
        //cerr<<"BIN"<<endl;
        //for(auto l:B[v[i]]->lines)debug(l);
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      //cerr<<"ADD:"<<v[i]<<" "<<B[v[i]]->query(v[i])<<endl;
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 1
time_ms: 1570
memory_kb: 125240
final_rank: 3

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)
#define ALL(v) v.begin(),v.end()

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    //cerr<<"query:"<<x<<endl;
    //for(const auto&l:lines)debug(l);
    //ll ress=val(0,x);
    //REP(i,lines.size())ress=min(ress,val(i,x));
    //cerr<<"res:"<<ress<<endl;
    int l=-1,r=lines.size()-1;
    ll res=min(val(0,x),val(r,x));
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x)){
        res=min(res,val(mid,x));
        r=mid;
      }
      else{
        res=min(res,val(mid+1,x));
        l=mid+1;
      }
    }
    //if(res!=ress)cerr<<"hogehogehogehoge"<<res<<endl;
    return res;
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,2*LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        vector<Line> vec;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)vec.push_back({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        sort(ALL(vec),[](const Line&a,const Line&b){return a.a>b.a;});

        for(const auto&[a,b]:vec)B[m]->push_back(a,b);

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
        //cerr<<"BIN"<<endl;
        //for(auto l:B[v[i]]->lines)debug(l);
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      //cerr<<"ADD:"<<v[i]<<" "<<B[v[i]]->query(v[i])<<endl;
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.5454545454545454
time_ms: 1620
memory_kb: 125260
final_rank: 8

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    ll res=min(val(0,x),val(r,x));
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x)){
        res=min(res,val(mid,x));
        r=mid;
      }
      else{
        res=min(res,val(mid+1,x));
        l=mid+1;
      }
    }
    return res;
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,2*LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
        //cerr<<"BIN"<<endl;
        //for(auto l:B[v[i]]->lines)debug(l);
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      //cerr<<"ADD:"<<v[i]<<" "<<B[v[i]]->query(v[i])<<endl;
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.5454545454545454
time_ms: 1570
memory_kb: 125256
final_rank: 7

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    ll res=min(val(0,x),val(r,x));
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x)){
        res=min(res,val(mid,x));
        r=mid;
      }
      else l=mid;
    }
    return res;
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,2*LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
        //cerr<<"BIN"<<endl;
        //for(auto l:B[v[i]]->lines)debug(l);
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      //cerr<<"ADD:"<<v[i]<<" "<<B[v[i]]->query(v[i])<<endl;
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.5454545454545454
time_ms: 1530
memory_kb: 125276
final_rank: 6

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.38636363636363635
time_ms: 1560
memory_kb: 125260
final_rank: 14

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int INF=1e9;
const long long LINF=1e15;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =INF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.38636363636363635
time_ms: 1560
memory_kb: 125308
final_rank: 15

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const long long LINF=1e15;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}
template<typename T>
bool chmin(T &a,T b){
  return (a>b&&(a=b,true));
}

struct Line{
  ll a,b;
  ll f(ll x){
    return a*x+b;
  }
};
void debug(const Line&l){
  cerr<<l.a<<"x+"<<l.b<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].a==a){
      if(lines[1].b<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().a==a){
      if(lines.back().b<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].f(x);
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};


struct LiChaoTree {
  int n;
  vector<ll> xs,p,q;
  vector<bool> u;
  int cnt;
  struct rireki{
    int cnt,k;
    ll prep,preq;
    bool preu;
  };
  stack<rireki> sta;

  LiChaoTree(int n0){
    n = 1;
    while(n < n0) n <<= 1;
    cnt=0;
    u.resize(n*2,false);xs.resize(n*2,0);p.resize(n*2,0);q.resize(n*2,LINF);
    for(int i=0; i<2*n; ++i) u[i] = false;
    for(int i=0; i<n0; ++i) xs[i] = i;
    for(int i=n0; i<2*n-1; ++i) xs[i] =LINF;
  }

  void _add_line(ll a, ll b, int k, int l, int r,int num) {
    while(r-l > 0) {
      int m = (l + r) >> 1;
      if(!u[k]) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        u[k] = true;
        return;
      }

      ll lx = xs[l], mx = xs[m], rx = xs[r-1];
      ll pk = p[k], qk = q[k];
      bool left = (a*lx+b < pk*lx+qk);
      bool mid = (a*mx+b < pk*mx+qk);
      bool right = (a*rx+b < pk*rx+qk);
      if(left && right) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        p[k] = a; q[k] = b;
        return;
      }
      if(!left && !right) {
        return;
      }
      if(mid) {
        sta.push(rireki{num,k,p[k],q[k],u[k]});
        swap(p[k], a);
        swap(q[k], b);
      }
      if(left != mid) {
        k = 2*k+1; r = m;
      } else {
        k = 2*k+2; l = m;
      }
    }
  }

  ll _query(int k, ll x) {
    k += n - 1;
    ll s = u[k] ? p[k]*x+q[k] :LINF;
    while(k > 0) {
      k = (k - 1) / 2;
      if(u[k]) {
        ll r = p[k]*x+q[k];
        s = min(s, r);
      }
    }
    return s;
  }

  void add_line(ll a, ll b) {
    _add_line(a, b, 0, 0, n,++cnt);
  }
  
  void undo(){
    int now=cnt--;
    while(sta.size() && sta.top().cnt==now){
      p[sta.top().k]=sta.top().prep;
      q[sta.top().k]=sta.top().preq;
      u[sta.top().k]=sta.top().preu;
      sta.pop();
    }
  }

  ll query(int i) {
    return _query(i,xs[i]);
  }
};

int main(){
  //cerr<<"HOGE"<<endl;
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  //cerr<<"HOGE"<<endl;
  int n,K;cin>>n>>K;//cerr<<"HOGE"<<endl;
  vector<ll> v(n);//cerr<<"HOGE"<<endl;
  REP(i,n)cin>>v[i];//cerr<<"HOGE"<<endl;

  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ
  //cerr<<"HOGE"<<endl;

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    //cerr<<"K;"<<k<<endl;
    LiChaoTree A(n+2);
    stack<Line> staA;
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      
      while(staA.size() and staA.top().a<=v[i]){
        staA.pop();
        A.undo();
      }
      A.add_line(v[i],B[v[i]]->query(v[i]));
      staA.push(Line{v[i],B[v[i]]->query(v[i])});
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //for(const auto&p:dp)cerr<<p<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.22727272727272727
time_ms: 1020
memory_kb: 93692
final_rank: 20

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
const long long LINF=1e15;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}

using Line=pair<ll,ll>;

void debug(const deque<Line> lines){
  for(const auto[a,b]:lines)cerr<<a<<"x+"<<b<<" ";cerr<<endl;
}

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].first==a){
      if(lines[1].second<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().first==a){
      if(lines.back().second<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].first*x+lines[id].second;
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  CHT A;//Mx+minを入れる
  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    while(A.lines.size())A.pop_back();
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        
        stack<Line> sta;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)sta.push({a,b});
            else B[m]->push_front(a,b);
          
          delete (it->second);
          it=B.erase(it);
        }

        while(sta.size()){
          auto [a,b]=sta.top();
          B[m]->push_back(a,b);
          sta.pop();
        }

        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      while(A.lines.size() and A.lines.back().first<=v[i])A.pop_back();
      A.push_back(v[i],B[v[i]]->query(v[i]));
      /*if(k==1&&i==5){
        for(const auto&[key,val]:B){
          cerr<<"KEY:"<<key<<endl;
          debug(val->lines);
        }
        debug(A.lines);
      }*/
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
    //REP(i,n+1)cerr<<dp[i]<<" ";cerr<<endl;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.38636363636363635
time_ms: 850
memory_kb: 82008
final_rank: 11

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
const long long LINF=1e15;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}

using Line=pair<ll,ll>;

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].first==a){
      if(lines[1].second<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().first==a){
      if(lines.back().second<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].first*x+lines[id].second;
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  CHT A;//Mx+minを入れる
  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    while(A.lines.size())A.pop_back();
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)B[m]->push_back(a,b);
            else B[m]->push_front(a,b);
          delete (it->second);
          it=B.erase(it);
        }
        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      while(A.lines.size() and A.lines.back().first<v[i])A.pop_back();
      A.push_back(v[i],B[v[i]]->query(v[i]));
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.38636363636363635
time_ms: 980
memory_kb: 82080
final_rank: 13

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ld=long double;
const long long LINF=1e18;
#define REP(i,n) for(int i=0;i<(n);i++)

template<typename T>
bool chmax(T &a,T b){
  return (a<b&&(a=b,true));
}

using Line=pair<ll,ll>;

struct CHT{
  deque<Line> lines;

  void push_front(ll a,ll b){
    while(lines.size()>=2){
      const auto&[a1,b1]=lines[0];
      const auto&[a2,b2]=lines[1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_front();
      else break;
    }
    if(lines.size()&&lines[0].first==a){
      if(lines[1].second<=b)return;
      lines.pop_front();
    }
    lines.push_front({a,b});
  }

  void push_back(ll a,ll b){
    while(lines.size()>=2){
      int S=lines.size();
      const auto&[a1,b1]=lines[S-2];
      const auto&[a2,b2]=lines[S-1];
      if((b1-b)*(a-a2)>(b2-b)*(a-a1))lines.pop_back();
      else break;
    }
    if(lines.size()&&lines.back().first==a){
      if(lines.back().second<=b)return;
      lines.pop_front();
    }
    lines.push_back({a,b});
  }

  void pop_back(){
    lines.pop_back();
  }

  inline ll val(int id,int x){
    return lines[id].first*x+lines[id].second;
  }
  ll query(int x){
    int l=-1,r=lines.size()-1;
    while(r-l>1){
      int mid=(l+r)>>1;
      if(val(mid,x)<val(mid+1,x))r=mid;
      else l=mid;
    }
    return val(r,x);
  }
};

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n,K;cin>>n>>K;
  vector<ll> v(n);
  REP(i,n)cin>>v[i];

  CHT A;//Mx+minを入れる
  map<int,CHT*> B;//B[m]:最大値がmの区間のやつ

  vector<ll> dp(n+1,LINF);//dp[i]:[0,i)をk個に区切った時の最小値
  dp[0]=0;
  REP(k,K){
    while(A.lines.size())A.pop_back();
    while(B.size()){
      delete B.begin()->second;
      B.erase(B.begin());
    }
    vector<ll> dp2(n+1,LINF);//dp2[i]:[0,i)をk+1個に区切った時の最小値
    
    
    for(int i=k;i<n;i++){
      if(!B.size()||(B.begin()->first)>v[i]){
        CHT *cht=new CHT();
        (*cht).push_back(-i,dp[i]);
        B[v[i]]=cht;
      }
      else{
        int sz=-1,m;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];it++)
          if(chmax(sz,(int)(it->second->lines.size())))m=it->first;
        for(auto it=B.begin();it!=B.end()&&(it->first)<=v[i];){
          const auto&key=it->first;
          if(key==m){
            ++it;
            continue;
          }
          for(const auto&[a,b]:it->second->lines)
            if(key<m)B[m]->push_back(a,b);
            else B[m]->push_front(a,b);
          delete (it->second);
          it=B.erase(it);
        }
        B[m]->push_back(-i,dp[i]);
        if(m!=v[i]){
          B[v[i]]=B[m];
          B.erase(m);
        }
      }
      while(A.lines.size() and A.lines.back().first<v[i])A.pop_back();
      A.push_back(v[i],B[v[i]]->query(v[i]));
      dp2[i+1]=A.query(i+1);
    }
    dp=dp2;
  }
  cout<<dp[n]<<endl;
}
accuracy: 0.38636363636363635
time_ms: 870
memory_kb: 82036
final_rank: 12

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree2 {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;

    DynamicLiChaoTree2() : root{nullptr} {}

    void rec_delete(Node *now) {
        if (!now)
            return;
        rec_delete(now->l), rec_delete(now->r);
        delete now;
    }

    void del() {
        rec_delete(root);
    }

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t) 
            return new Node(x);

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r) --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t) return id;
        if (l == r) return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r) --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const { return query(root, 0, ca.size() - 1, x); }
};
using DLT2 = DynamicLiChaoTree2<ll, (ll)1e18>;

template <typename T, T x_low, T x_high, T id>
struct DynamicLiChaoTree {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const {
            return a * x + b;
        }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;
    vector<vector<pair<Node *, Line>>> update;

    DynamicLiChaoTree() : root{nullptr} {}

    void rec_delete(Node *now) {
        if (!now)
            return;
        rec_delete(now->l), rec_delete(now->r);
        delete now;
    }

    ~DynamicLiChaoTree() {
        rec_delete(root);
    }

    Node *add_line(Node *t, Line &x, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (!t) {
            auto nt = new Node(x);
            update.back().pb(nt, Line(0, id));
            return nt;
        }

        T t_l = t->x.get(l), t_r = t->x.get(r);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            update.back().pb(t, t->x);
            t->x = x;
            return t;
        } else {
            T m = (l + r) / 2;
            if (m == r)
                --m;
            T t_m = t->x.get(m), x_m = x.get(m);
            if (t_m > x_m) {
                update.back().pb(t, t->x);
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a, t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a, x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        update.pb();
        Line x(a, b);
        root = add_line(root, x, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    void rollback() {
        for(auto &[t, x] : update.back())
            t->x = x;
        update.pop_back();
    }

    Node *add_segment(Node *t, Line &x, const T &a, const T &b, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (r < a || b < l)
            return t;
        if (a <= l && r <= b) {
            Line y{x};
            return add_line(t, y, l, r, x_l, x_r);
        }
        if (t) {
            T t_l = t->x.get(l), t_r = t->x.get(r);
            if (t_l <= x_l && t_r <= x_r)
                return t;
        } else {
            t = new Node(Line(0, id));
        }
        T m = (l + r) / 2;
        if (m == r)
            --m;
        T x_m = x.get(m);
        t->l = add_segment(t->l, x, a, b, l, m, x_l, x_m);
        t->r = add_segment(t->r, x, a, b, m + 1, r, x_m + x.a, x_r);
        return t;
    }

    void add_segment(const T &l, const T &r, const T &a, const T &b) {
        Line x(a, b);
        root = add_segment(root, x, l, r - 1, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    T query(const Node *t, const T &l, const T &r, const T &x) const {
        if (!t)
            return id;
        if (l == r)
            return t->x.get(x);
        T m = (l + r) / 2;
        if (m == r)
            --m;
        if (x <= m)
            return min(t->x.get(x), query(t->l, l, m, x));
        else
            return min(t->x.get(x), query(t->r, m + 1, r, x));
    }

    T query(const T &x) const {
        return query(root, x_low, x_high, x);
    }
};
using DLT = DynamicLiChaoTree<ll, 0ll, (ll)1e5, (ll)1e18>;

vector<ll> dp, ndp;

struct unko {
    ll a;
    DLT2 cht;
    int l, r;
    unko(ll a, int idx) : a(a), l(idx), r(idx + 1) {
        cht.add_line(-idx, dp[idx]);
    }
};

void merge(unko &a, unko &b) {
    ll ma = a.a;
    if (a.r - a.l < b.r - b.l)
        swap(a, b);
    for (int idx = b.l; idx < b.r; idx++)
        a.cht.add_line(-idx, dp[idx]);
    chmin(a.l, b.l), chmax(a.r, b.r);
    a.a = ma;
}
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    auto cca = a;
    sort(all(cca));
    ca.pb(cca[0]);
    REP(i, 1, n) if (cca[i] != cca[i - 1]) ca.pb(cca[i]);
    unordered_map<int, int> ra;
    rep(i, ca.size()) ra[ca[i]] = i;
    dp.resize(n + 1, 1e18);
    ndp.resize(n + 1);
    dp[0] = 0;
    rep(j, k) {
        fill(all(ndp), 1e18);
        stack<int> st;
        vector<unko> us;
        DLT cht;
        rep(i, n) {
            unko y(a[i], i);
            while (!st.empty()) {
                auto num = st.top();
                auto &x = us[num];
                if (x.a > y.a)
                    break;
                st.pop();
                cht.rollback();
                merge(y, x);
            }
            st.push(us.size());
            us.pb(y);
            cht.add_line(y.a, y.cht.query(ra[y.a]));
            ndp[i + 1] = cht.query(i + 1);
        }
        for(auto &uk : us)
            uk.cht.del();
        swap(dp, ndp);
    }
    cout << dp[n] << endl;
}
accuracy: 1
time_ms: 890
memory_kb: 48584
final_rank: 2

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree2 {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;

    DynamicLiChaoTree2() : root{nullptr} {}

    void rec_delete(Node *now) {
        if (!now)
            return;
        rec_delete(now->l), rec_delete(now->r);
        delete now;
    }

    void del() {
        rec_delete(root);
    }

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t) 
            return new Node(x);

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r) --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t) return id;
        if (l == r) return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r) --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const { return query(root, 0, ca.size() - 1, x); }
};
using DLT2 = DynamicLiChaoTree2<ll, (ll)1e18>;

template <typename T, T x_low, T x_high, T id>
struct DynamicLiChaoTree {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const {
            return a * x + b;
        }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;
    vector<Node *> Nodes;
    vector<vector<pair<Node *, Line>>> update;

    DynamicLiChaoTree() : root{nullptr} {}
    ~DynamicLiChaoTree() {
        for(auto &e: Nodes)
            delete e;
    }

    Node *add_line(Node *t, Line &x, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (!t) {
            Nodes.pb(new Node(x));
            update.back().pb(Nodes.back(), Line(0, id));
            return Nodes.back();
        }

        T t_l = t->x.get(l), t_r = t->x.get(r);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            update.back().pb(t, t->x);
            t->x = x;
            return t;
        } else {
            T m = (l + r) / 2;
            if (m == r)
                --m;
            T t_m = t->x.get(m), x_m = x.get(m);
            if (t_m > x_m) {
                update.back().pb(t, t->x);
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a, t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a, x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        update.pb();
        Line x(a, b);
        root = add_line(root, x, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    void rollback() {
        for(auto &[t, x] : update.back())
            t->x = x;
        update.pop_back();
    }

    Node *add_segment(Node *t, Line &x, const T &a, const T &b, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (r < a || b < l)
            return t;
        if (a <= l && r <= b) {
            Line y{x};
            return add_line(t, y, l, r, x_l, x_r);
        }
        if (t) {
            T t_l = t->x.get(l), t_r = t->x.get(r);
            if (t_l <= x_l && t_r <= x_r)
                return t;
        } else {
            t = new Node(Line(0, id));
        }
        T m = (l + r) / 2;
        if (m == r)
            --m;
        T x_m = x.get(m);
        t->l = add_segment(t->l, x, a, b, l, m, x_l, x_m);
        t->r = add_segment(t->r, x, a, b, m + 1, r, x_m + x.a, x_r);
        return t;
    }

    void add_segment(const T &l, const T &r, const T &a, const T &b) {
        Line x(a, b);
        root = add_segment(root, x, l, r - 1, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    T query(const Node *t, const T &l, const T &r, const T &x) const {
        if (!t)
            return id;
        if (l == r)
            return t->x.get(x);
        T m = (l + r) / 2;
        if (m == r)
            --m;
        if (x <= m)
            return min(t->x.get(x), query(t->l, l, m, x));
        else
            return min(t->x.get(x), query(t->r, m + 1, r, x));
    }

    T query(const T &x) const {
        return query(root, x_low, x_high, x);
    }
};
using DLT = DynamicLiChaoTree<ll, 0ll, (ll)1e5, (ll)1e18>;

vector<ll> dp, ndp;

struct unko {
    ll a;
    DLT2 cht;
    int l, r;
    unko(ll a, int idx) : a(a), l(idx), r(idx + 1) {
        cht.add_line(-idx, dp[idx]);
    }
};

void merge(unko &a, unko &b) {
    ll ma = a.a;
    if (a.r - a.l < b.r - b.l)
        swap(a, b);
    for (int idx = b.l; idx < b.r; idx++)
        a.cht.add_line(-idx, dp[idx]);
    chmin(a.l, b.l), chmax(a.r, b.r);
    a.a = ma;
}
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    auto cca = a;
    sort(all(cca));
    ca.pb(cca[0]);
    REP(i, 1, n) if (cca[i] != cca[i - 1]) ca.pb(cca[i]);
    unordered_map<int, int> ra;
    rep(i, ca.size()) ra[ca[i]] = i;
    dp.resize(n + 1, 1e18);
    ndp.resize(n + 1);
    dp[0] = 0;
    rep(j, k) {
        fill(all(ndp), 1e18);
        stack<int> st;
        vector<unko> us;
        DLT cht;
        rep(i, n) {
            unko y(a[i], i);
            while (!st.empty()) {
                auto num = st.top();
                auto &x = us[num];
                if (x.a > y.a)
                    break;
                st.pop();
                cht.rollback();
                merge(y, x);
            }
            st.push(us.size());
            us.pb(y);
            cht.add_line(y.a, y.cht.query(ra[y.a]));
            ndp[i + 1] = cht.query(i + 1);
        }
        for(auto &uk : us)
            uk.cht.del();
        swap(dp, ndp);
    }
    cout << dp[n] << endl;
}
accuracy: 1
time_ms: 870
memory_kb: 49812
final_rank: 1

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree2 {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;
    vector<Node *> Nodes;

    DynamicLiChaoTree2() : root{nullptr} {}
    void del() {
        for(auto &e: Nodes)
            delete e;
    }

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t) {
            // Nodes.pb(new Node(x));
            // return Nodes.back();
            return new Node(x);
        }

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r) --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t) return id;
        if (l == r) return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r) --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const { return query(root, 0, ca.size() - 1, x); }
};
using DLT2 = DynamicLiChaoTree2<ll, (ll)1e18>;

template <typename T, T x_low, T x_high, T id>
struct DynamicLiChaoTree {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {
        }

        inline T get(T x) const {
            return a * x + b;
        }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;
    vector<Node *> Nodes;
    vector<vector<pair<Node *, Line>>> update;

    DynamicLiChaoTree() : root{nullptr} {}
    ~DynamicLiChaoTree() {
        for(auto &e: Nodes)
            delete e;
    }

    Node *add_line(Node *t, Line &x, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (!t) {
            Nodes.pb(new Node(x));
            update.back().pb(Nodes.back(), Line(0, id));
            return Nodes.back();
        }

        T t_l = t->x.get(l), t_r = t->x.get(r);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            update.back().pb(t, t->x);
            t->x = x;
            return t;
        } else {
            T m = (l + r) / 2;
            if (m == r)
                --m;
            T t_m = t->x.get(m), x_m = x.get(m);
            if (t_m > x_m) {
                update.back().pb(t, t->x);
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a, t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a, x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        update.pb();
        Line x(a, b);
        root = add_line(root, x, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    void rollback() {
        for(auto &[t, x] : update.back())
            t->x = x;
        update.pop_back();
    }

    Node *add_segment(Node *t, Line &x, const T &a, const T &b, const T &l, const T &r, const T &x_l, const T &x_r) {
        if (r < a || b < l)
            return t;
        if (a <= l && r <= b) {
            Line y{x};
            return add_line(t, y, l, r, x_l, x_r);
        }
        if (t) {
            T t_l = t->x.get(l), t_r = t->x.get(r);
            if (t_l <= x_l && t_r <= x_r)
                return t;
        } else {
            t = new Node(Line(0, id));
        }
        T m = (l + r) / 2;
        if (m == r)
            --m;
        T x_m = x.get(m);
        t->l = add_segment(t->l, x, a, b, l, m, x_l, x_m);
        t->r = add_segment(t->r, x, a, b, m + 1, r, x_m + x.a, x_r);
        return t;
    }

    void add_segment(const T &l, const T &r, const T &a, const T &b) {
        Line x(a, b);
        root = add_segment(root, x, l, r - 1, x_low, x_high, x.get(x_low), x.get(x_high));
    }

    T query(const Node *t, const T &l, const T &r, const T &x) const {
        if (!t)
            return id;
        if (l == r)
            return t->x.get(x);
        T m = (l + r) / 2;
        if (m == r)
            --m;
        if (x <= m)
            return min(t->x.get(x), query(t->l, l, m, x));
        else
            return min(t->x.get(x), query(t->r, m + 1, r, x));
    }

    T query(const T &x) const {
        return query(root, x_low, x_high, x);
    }
};
using DLT = DynamicLiChaoTree<ll, 0ll, (ll)1e5, (ll)1e18>;

vector<ll> dp, ndp;

struct unko {
    ll a;
    DLT2 cht;
    int l, r;
    unko(ll a, int idx) : a(a), l(idx), r(idx + 1) {
        cht.add_line(-idx, dp[idx]);
    }
};

void merge(unko &a, unko &b) {
    ll ma = a.a;
    if (a.r - a.l < b.r - b.l)
        swap(a, b);
    for (int idx = b.l; idx < b.r; idx++)
        a.cht.add_line(-idx, dp[idx]);
    chmin(a.l, b.l), chmax(a.r, b.r);
    a.a = ma;
}
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    auto cca = a;
    sort(all(cca));
    ca.pb(cca[0]);
    REP(i, 1, n) if (cca[i] != cca[i - 1]) ca.pb(cca[i]);
    unordered_map<int, int> ra;
    rep(i, ca.size()) ra[ca[i]] = i;
    dp.resize(n + 1, 1e18);
    ndp.resize(n + 1);
    dp[0] = 0;
    rep(j, k) {
        fill(all(ndp), 1e18);
        stack<int> st;
        vector<unko> us;
        DLT cht;
        rep(i, n) {
            unko y(a[i], i);
            while (!st.empty()) {
                auto num = st.top();
                auto &x = us[num];
                if (x.a > y.a)
                    break;
                st.pop();
                cht.rollback();
                merge(y, x);
            }
            st.push(us.size());
            us.pb(y);
            cht.add_line(y.a, y.cht.query(ra[y.a]));
            ndp[i + 1] = cht.query(i + 1);
        }
        for(auto &uk : us)
            uk.cht.del();
        swap(dp, ndp);
    }
    cout << dp[n] << endl;
}
accuracy: 1
time_ms: 970
memory_kb: 194624
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < n; i++)
#define rep2(i, x, n) for (int i = x; i <= n; i++)
#define rep3(i, x, n) for (int i = x; i >= n; i--)
#define each(e, v) for (auto &e : v)
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
bool chmax(T &x, const T &y) {
    return (x < y) ? (x = y, true) : false;
}

template <typename T>
bool chmin(T &x, const T &y) {
    return (x > y) ? (x = y, true) : false;
}

template <typename T>
int flg(T x, int i) {
    return (x >> i) & 1;
}

template <typename T>
void print(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (v.empty()) cout << '\n';
}

template <typename T>
void printn(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << '\n';
}

template <typename T>
int lb(const vector<T> &v, T x) {
    return lower_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
int ub(const vector<T> &v, T x) {
    return upper_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
void rearrange(vector<T> &v) {
    sort(begin(v), end(v));
    v.erase(unique(begin(v), end(v)), end(v));
}

template <typename T>
vector<int> id_sort(const vector<T> &v, bool greater = false) {
    int n = v.size();
    vector<int> ret(n);
    iota(begin(ret), end(ret), 0);
    sort(begin(ret), end(ret), [&](int i, int j) { return greater ? v[i] > v[j] : v[i] < v[j]; });
    return ret;
}

template <typename S, typename T>
pair<S, T> operator+(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first + q.first, p.second + q.second);
}

template <typename S, typename T>
pair<S, T> operator-(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first - q.first, p.second - q.second);
}

template <typename S, typename T>
istream &operator>>(istream &is, pair<S, T> &p) {
    S a;
    T b;
    is >> a >> b;
    p = make_pair(a, b);
    return is;
}

template <typename S, typename T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
    return os << p.first << ' ' << p.second;
}

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

const int inf = (1 << 30) - 1;
const ll INF = (1LL << 60) - 1;
const int MOD = 1000000007;
// const int MOD = 998244353;

template <typename T, bool ismin = true>
struct Convex_Hull_Trick {
    vector<T> a, b; // y = ax+b
    deque<int> que;

    Convex_Hull_Trick(){};

    bool empty() const { return que.empty(); }

    T f(int i, const T &x) const { return a[i] * x + b[i]; }

    bool judge(int i, int j, int k) const { return (b[k] - b[j]) * (a[j] - a[i]) >= (b[j] - b[i]) * (a[k] - a[j]); }

    void add_line_left(T p, T q) {
        if (!ismin) p *= -1, q *= -1;
        int k = a.size();
        a.push_back(p), b.push_back(q);
        while (que.size() >= 2 && judge(k, que[0], que[1])) que.pop_front();
        que.push_front(k);
    }

    void add_line_right(T p, T q) {
        if (!ismin) p *= -1, q *= -1;
        // assert(empty() || a.back() >= p);
        int k = a.size();
        a.push_back(p), b.push_back(q);
        if (!empty() && a[que.back()] == p) {
            if (b[que.back()] <= q) return;
            que.pop_back();
        }
        while (que.size() >= 2 && judge(que[que.size() - 2], que[que.size() - 1], k)) que.pop_back();
        que.push_back(k);
    }

    T query(T x) {
        assert(!empty());
        int l = 0, r = que.size();
        while (r - l > 1) {
            int m = (l + r) / 2;
            (f(que[m - 1], x) >= f(que[m], x) ? l : r) = m;
        }
        return ismin ? f(que[l], x) : -f(que[l], x);
    }

    T query_monotone_inc(T x) {
        assert(!empty());
        while (que.size() >= 2 && f(que[0], x) >= f(que[1], x)) que.pop_front();
        return ismin ? f(que[0], x) : -f(que[0], x);
    }

    T query_monotone_dec(T x) {
        assert(!empty());
        while (que.size() >= 2 && f(que[que.size() - 1], x) >= f(que[que.size() - 2], x)) que.pop_back();
        return ismin ? f(que[que.size() - 1], x) : -f(que[que.size() - 1], x);
    }
};

template <typename T, bool is_min = true>
struct Li_Chao_Tree {
    const T INF_T = numeric_limits<T>::max() / 2;
    vector<T> as, bs;
    int n;

    vector<int> ts;
    vector<int> pre_id;
    vector<T> pre_a, pre_b;

    Li_Chao_Tree(int m) {
        n = 1;
        while (n < m) n <<= 1;
        as.assign(2 * n, 0), bs.assign(2 * n, INF_T);
    }

    void add_line(const T &a, const T &b, int ti, int i, const T &l, const T &r) {
        ts.push_back(ti);
        pre_id.push_back(i);
        pre_a.push_back(as[i]), pre_b.push_back(bs[i]);
        T l1 = as[i] * l + bs[i], l2 = a * l + b;
        T r1 = as[i] * r + bs[i], r2 = a * r + b;
        if (l1 <= l2 && r1 <= r2) return;
        if (l1 >= l2 && r1 >= r2) {
            as[i] = a, bs[i] = b;
            return;
        }
        T m = (l + r - 1) / 2;
        T m1 = as[i] * m + bs[i], m2 = a * m + b;
        if (m1 > m2) {
            if (l1 <= l2) {
                add_line(as[i], bs[i], ti, 2 * i, l, m);
            } else {
                add_line(as[i], bs[i], ti, 2 * i + 1, m + 1, r);
            }
            as[i] = a, bs[i] = b;
        } else {
            if (l1 >= l2) {
                add_line(a, b, ti, 2 * i, l, m);
            } else {
                add_line(a, b, ti, 2 * i + 1, m + 1, r);
            }
        }
    }

    void add_line(const T &a, const T &b, int ti) { // 直線 y = ax+b を追加
        add_line(is_min ? a : -a, is_min ? b : -b, ti, 1, 0, n - 1);
    }

    T query(const T &x, int i, const T &l, const T &r) const {
        if (l == r) return as[i] * x + bs[i];
        T m = (l + r - 1) / 2;
        if (x <= m) return min(as[i] * x + bs[i], query(x, 2 * i, l, m));
        return min(as[i] * x + bs[i], query(x, 2 * i + 1, m + 1, r));
    }

    T query(const T &x) const {
        T ret = query(x, 1, 0, n - 1);
        return is_min ? ret : -ret;
    }

    void undo(const int &t) {
        while (!empty(ts)) {
            int k = sz(ts) - 1;
            if (ts[k] != t) break;
            int i = pre_id[k];
            as[i] = pre_a[k], bs[i] = pre_b[k];
            ts.pop_back();
            pre_id.pop_back();
            pre_a.pop_back(), pre_b.pop_back();
        }
    }
};

vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree {
    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;

    DynamicLiChaoTree() : root{nullptr} {}

    //~DynamicLiChaoTree() { rec_delete(root); }

    void rec_delete(Node *now) {
        if (!now) return;
        rec_delete(now->l), rec_delete(now->r);
        delete now;
    }

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t) return new Node(x);

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r) --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t) return id;
        if (l == r) return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r) --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const { return query(root, 0, ca.size() - 1, x); }
};

using DLT = DynamicLiChaoTree<ll, INF>;

vector<vector<ll>> dp;

struct Data {
    int l, r;
    vector<DLT> cht;

    Data(int L, int R, int i) : cht(R - L) {
        l = i, r = i + 1;
        rep(j, R - L) cht[j].add_line(-i, dp[L + j][i]);
    }

    Data() {}
};

void merge(Data &a, Data &b, int L, int R) {
    if (a.r - a.l > b.r - b.l) {
        for (int i = b.l; i < b.r; i++) { rep(j, R - L) a.cht[j].add_line(-i, dp[L + j][i]); }
    } else {
        for (int i = a.l; i < a.r; i++) { rep(j, R - L) b.cht[j].add_line(-i, dp[L + j][i]); }
        swap(a, b);
    }
    chmin(a.l, b.l), chmax(a.r, b.r);
}

int main() {
    int N, K;
    cin >> N >> K;

    vector<ll> a(N);
    rep(i, N) cin >> a[i];
    ca = a;
    rearrange(ca);

    dp.assign(K + 1, vector<ll>(N + 1, INF));
    rep(i, K + 1) dp[i][0] = 0;

    int D = 1;
    int L = 0;

    for (int L = 0; L < K; L += D) {
        int R = min(K, L + D);
        stack<int> st;
        vector<Data> ds(N);
        vector<Li_Chao_Tree<ll>> lct(R - L, N + 1);
        rep(i, N) {
            Data y(L, R, i);
            while (!empty(st)) {
                int x = st.top();
                if (a[x] > a[i]) break;
                st.pop();
                merge(y, ds[x], L, R);
                rep(j, R - L) lct[j].undo(x);
                // cout << i << ' ' << x << '\n';
            }
            st.push(i);
            ds[i] = y;

            rep(j, R - L) {
                ll tmp = y.cht[j].query(lb(ca, a[i]));
                if (tmp < INF / 2) lct[j].add_line(a[i], tmp, i);
                dp[L + j + 1][i + 1] = lct[j].query(i + 1);
            }
        }
    }

    // rep(i, K + 1) print(dp[i]);
    cout << dp[K][N] << '\n';
}
accuracy: 1
time_ms: 1090
memory_kb: 209412
final_rank: 5

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++) cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return (false);
        if (data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0) return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) { return (-data[find(k)]); }

    bool same(int x, int y) { return find(x) == find(y); }

    int operator[](int k) { return find(k); }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {}

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    static int get_mod() { return mod; }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod) x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() { return *this += Mod_Int(1); }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() { return *this -= Mod_Int(1); }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const { return Mod_Int(-x); }

    Mod_Int operator+(const Mod_Int &p) const { return Mod_Int(*this) += p; }

    Mod_Int operator-(const Mod_Int &p) const { return Mod_Int(*this) -= p; }

    Mod_Int operator*(const Mod_Int &p) const { return Mod_Int(*this) *= p; }

    Mod_Int operator/(const Mod_Int &p) const { return Mod_Int(*this) /= p; }

    bool operator==(const Mod_Int &p) const { return x == p.x; }

    bool operator!=(const Mod_Int &p) const { return x != p.x; }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1) ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) { return os << p.x; }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1) ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0) u += mod;
    return u;
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1) ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
template <typename T, bool ismin = true>
struct Convex_Hull_Trick {
    vector<T> a, b; // y = ax+b
    deque<int> que;

    Convex_Hull_Trick(){};

    bool empty() const { return que.empty(); }

    T f(int i, const T &x) const { return a[i] * x + b[i]; }

    bool judge(int i, int j, int k) const { return (b[k] - b[j]) * (a[j] - a[i]) >= (b[j] - b[i]) * (a[k] - a[j]); }

    void add_line(T p, T q) {
        if (!ismin) p *= -1, q *= -1;
        // assert(empty() || a.back() >= p);
        int k = a.size();
        a.push_back(p), b.push_back(q);
        if (!empty() && a[que.back()] == p) {
            if (b[que.back()] <= q) return;
            que.pop_back();
        }
        while (que.size() >= 2 && judge(que[que.size() - 2], que[que.size() - 1], k)) que.pop_back();
        que.push_back(k);
    }

    void pop_line(T p) {
        if (!ismin) p *= -1;
        if (!empty() && a[que.back()] == p) {
            que.pop_back();
            // a.pop_back(), b.pop_back();
        }
    }

    T query(T x) {
        assert(!empty());
        int l = 0, r = que.size();
        while (r - l > 1) {
            int m = (l + r) / 2;
            (f(que[m - 1], x) >= f(que[m], x) ? l : r) = m;
        }
        return ismin ? f(que[l], x) : -f(que[l], x);
    }

    T query_monotone_inc(T x) {
        assert(!empty());
        while (que.size() >= 2 && f(que[0], x) >= f(que[1], x)) que.pop_front();
        return ismin ? f(que[0], x) : -f(que[0], x);
    }

    T query_monotone_dec(T x) {
        assert(!empty());
        while (que.size() >= 2 && f(que[que.size() - 1], x) >= f(que[que.size() - 2], x)) que.pop_back();
        return ismin ? f(que[que.size() - 1], x) : -f(que[que.size() - 1], x);
    }
};

vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;

    DynamicLiChaoTree() : root{nullptr} {}

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t) return new Node(x);

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r) --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t) return id;
        if (l == r) return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r) --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const { return query(root, 0, ca.size() - 1, x); }
};
using DLT = DynamicLiChaoTree<ll, (ll)8e18>;

vector<Convex_Hull_Trick<ll>> cht;
vector<vector<ll>> dp;

struct unko {
    ll a;
    vector<int> p;
    vector<DLT> cht;
    unko(ll a, int idx, int k) : a(a), p(1, idx), cht(k) { rep(i, k) cht[i].add_line(-idx, dp[idx][i]); }
};

void merge(unko &a, unko &b) {
    ll ma = a.a;
    if (a.p.size() < b.p.size()) swap(a, b);
    for (auto idx : b.p) {
        rep(i, a.cht.size()) a.cht[i].add_line(-idx, dp[idx][i]);
        a.p.pb(idx);
    }
    a.a = ma;
}
// ----- library -------

ll gutyoku(int N, int K, vector<int> v) {
    int INF = (1LL << 30) - 1;
    vector<vector<int>> dp2(N + 1, vector<int>(K + 1, INF));
    for (int j = 0; j <= K; j++) dp2[0][j] = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < K; j++) {
            if (dp2[i][j] == INF) continue;
            int ma = 0;
            for (int k = i + 1; k <= N; k++) {
                ma = max(ma, v[k - 1]);
                dp2[k][j + 1] = min(dp2[k][j + 1], dp2[i][j] + ma * (k - i));
            }
        }
    }
    // rep(j, N + 1) print(dp2[j]);
    return dp2[N][K];
}

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    // cout << gutyoku(n, k, a) << '\n';
    auto cca = a;
    sort(all(cca));
    ca.pb(cca[0]);
    REP(i, 1, n) if (cca[i] != cca[i - 1]) ca.pb(cca[i]);
    unordered_map<int, int> ra;
    rep(i, ca.size()) ra[ca[i]] = i;
    cht.resize(k);
    dp.resize(n + 1, vector<ll>(k + 1, 8e18));
    rep(j, k + 1) dp[0][j] = 0;
    stack<int> st;
    vector<unko> us;
    rep(i, n) {
        unko y(a[i], i, k);
        while (!st.empty()) {
            auto num = st.top();
            auto &x = us[num];
            if (x.a > y.a) break;
            st.pop();
            rep(j, k) cht[j].pop_line(x.a);
            merge(y, x);
        }
        us.pb(y);
        st.push(us.size() - 1);
        rep(j, k) {
            // cout << i << ' ' << j << ' ' << y.a << ' ' << y.cht[j].query(ra[y.a]) << '\n';
            cht[j].add_line(y.a, y.cht[j].query(ra[y.a]));
        }
        rep(j, k) dp[i + 1][j + 1] = cht[j].query(i + 1);
    }
    // rep(j, n + 1) print(dp[j]);
    cout << dp[n][k] << endl;
}
accuracy: 0.5454545454545454
time_ms: 1770
memory_kb: 244040
final_rank: 9

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define lscan(x) scanf("%I64d", &x)
#define lprint(x) printf("%I64d", x)
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define rep2(i, n) for (ll i = (ll)n - 1; i >= 0; i--)
#define REP(i, l, r) for (ll i = l; i < (r); i++)
#define REP2(i, l, r) for (ll i = (ll)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<ll> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    ll size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return ans;
}

// ----- library -------
template <typename T, bool ismin = true>
struct Convex_Hull_Trick {
    vector<T> a, b; // y = ax+b
    deque<int> que;

    Convex_Hull_Trick(){};

    bool empty() const {
        return que.empty();
    }

    T f(int i, const T &x) const {
        return a[i] * x + b[i];
    }

    bool judge(int i, int j, int k) const {
        return (b[k] - b[j]) * (a[j] - a[i]) >= (b[j] - b[i]) * (a[k] - a[j]);
    }

    void add_line(T p, T q) {
        if (!ismin)
            p *= -1, q *= -1;
        // assert(empty() || a.back() >= p);
        int k = a.size();
        a.push_back(p), b.push_back(q);
        if (!empty() && a[que.back()] == p) {
            if (b[que.back()] <= q)
                return;
            que.pop_back();
        }
        while (que.size() >= 2 && judge(que[que.size() - 2], que[que.size() - 1], k))
            que.pop_back();
        que.push_back(k);
    }

    void pop_line(T p) {
        if (!ismin)
            p *= -1;
        if (!empty() && a[que.back()] == p) {
            que.pop_back();
            // a.pop_back(), b.pop_back();
        }
    }

    T query_monotone_inc(T x) {
        assert(!empty());
        while (que.size() >= 2 && f(que[0], x) >= f(que[1], x))
            que.pop_front();
        return ismin ? f(que[0], x) : -f(que[0], x);
    }
};

vector<ll> ca;

template <typename T, T id>
struct DynamicLiChaoTree {

    struct Line {
        T a, b;

        Line(T a, T b) : a(a), b(b) {}

        inline T get(T x) const {
            return a * x + b;
        }
    };

    struct Node {
        Line x;
        Node *l, *r;

        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };

    Node *root;

    DynamicLiChaoTree() : root{nullptr} {}

    Node *add_line(Node *t, Line &x, const int &l, const int &r, const T &x_l, const T &x_r) {
        if (!t)
            return new Node(x);

        T t_l = t->x.get(ca[l]), t_r = t->x.get(ca[r]);

        if (t_l <= x_l && t_r <= x_r) {
            return t;
        } else if (t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            int m = (l + r) / 2;
            if (m == r)
                --m;
            T t_m = t->x.get(ca[m]), x_m = x.get(ca[m]);
            if (t_m > x_m) {
                swap(t->x, x);
                if (x_l >= t_l)
                    t->l = add_line(t->l, x, l, m, t_l, t_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, t_m + x.a * (ca[m + 1] - ca[m]), t_r);
            } else {
                if (t_l >= x_l)
                    t->l = add_line(t->l, x, l, m, x_l, x_m);
                else
                    t->r = add_line(t->r, x, m + 1, r, x_m + x.a * (ca[m + 1] - ca[m]), x_r);
            }
            return t;
        }
    }

    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, 0, ca.size() - 1, x.get(ca[0]), x.get(ca[ca.size() - 1]));
    }

    T query(const Node *t, const int &l, const int &r, const int &x) const {
        if (!t)
            return id;
        if (l == r)
            return t->x.get(ca[x]);
        int m = (l + r) / 2;
        if (m == r)
            --m;
        if (x <= m)
            return min(t->x.get(ca[x]), query(t->l, l, m, x));
        else
            return min(t->x.get(ca[x]), query(t->r, m + 1, r, x));
    }

    T query(const int &x) const {
        return query(root, 0, ca.size() - 1, x);
    }
};
using DLT = DynamicLiChaoTree<ll, (ll)8e18>;

vector<Convex_Hull_Trick<ll>> cht;
vector<vector<ll>> dp;

struct unko {
    ll a;
    vector<int> p;
    vector<DLT> cht;
    unko(ll a, int idx, int k) : a(a), p(1, idx), cht(k) {
        rep(i, k) cht[i].add_line(-idx, dp[idx][i]);
    }
};

void merge(unko &a, unko &b) {
    ll ma = a.a;
    if (a.p.size() < b.p.size())
        swap(a, b);
    for (auto idx : b.p) {
        rep(i, a.cht.size()) a.cht[i].add_line(-idx, dp[idx][i]);
        a.p.pb(idx);
    }
    a.a = ma;
}
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    auto cca = a;
    sort(all(cca));
    ca.pb(cca[0]);
    REP(i, 1, n) if (cca[i] != cca[i - 1]) ca.pb(cca[i]);
    unordered_map<int, int> ra;
    rep(i, ca.size()) ra[ca[i]] = i;
    cht.resize(k);
    dp.resize(n + 1, vector<ll>(k + 1, 8e18));
    rep(j, k + 1) dp[0][j] = 0;
    stack<int> st;
    vector<unko> us;
    rep(i, n) {
        unko y(a[i], i, k);
        while (!st.empty()) {
            auto num = st.top();
            auto &x = us[num];
            if (x.a > y.a)
                break;
            st.pop();
            rep(j, k) cht[j].pop_line(x.a);
            merge(y, x);
        }
        us.pb(y);
        st.push(us.size() - 1);
        rep(j, k) cht[j].add_line(y.a, y.cht[j].query(ra[y.a]));
        rep(j, k) dp[i + 1][j + 1] = cht[j].query_monotone_inc(i + 1);
    }
    cout << dp[n][k] << endl;
}
accuracy: 0.5454545454545454
time_ms: 1810
memory_kb: 244428
final_rank: 10