Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

オレンジの出荷(Oranges)

あなたはJuicy Orange Industry 社を知っているだろうか? この会社の業務は美味しいオレンジを栽培して出荷することである．ここでは略してJOI 社と呼ぶ．

JOI 社では，収穫された $N$ 個のオレンジを箱詰めして出荷することになった．オレンジは工場にあるベルトコンベアの上に並べられており，ベルトコンベアの前から順番に $1$ から $N$ までの番号が付けられている．オレンジは大小さまざまであり，オレンジ $i$ $(1 \leq i \leq N)$ の大きさは $A_i$ である．

これらのオレンジを前から順番にいくつかの箱に分けて詰める．ひとつの箱には連続した番号のオレンジしか詰めることができない．

ひとつの箱には最大で $M$ 個までのオレンジを詰めることができる．ある箱にいくつかのオレンジを詰めるためにかかるコストは，箱に詰める最大のオレンジの大きさを $a$，箱に詰める最小のオレンジの大きさを $b$，箱に詰めるオレンジの個数を $s$ としたときに，$K + s \times (a - b)$ で求めることができる．ここで，$K$ は箱にかかるコストであり，すべての箱で共通の値である．

適切な個数の箱を用意して，すべてのオレンジを適切に箱詰めすることで，箱詰めにかかるコストの総和をできるだけ小さくしたい．

課題

ベルトコンベア上に並んでいるオレンジの情報と，ひとつの箱に詰められるオレンジの個数の最大値および，箱にかかるコストが与えられたとき，箱詰めにかかるコストの総和の最小値を求めるプログラムを作成せよ．

入力

標準入力から以下の入力を読み込め．

1 行目には，3 個の整数 $N, M, K$ が空白を区切りとして書かれている．これは，オレンジが $N$ 個あり，ひとつの箱に詰められるオレンジの個数の最大値が $M$ であって，箱にかかるコストが $K$ であることを表す．

続く $N$ 行のうちの $i$ 行目 $(1 \leq i \leq N)$ には，整数 $A_i$ が書かれている．これは，オレンジ $i$ の大きさが $A_i$ であることを表す．

出力

標準出力に，箱詰めにかかるコストの総和の最小値を 1 行で出力せよ．

制限

すべての入力データは以下の条件を満たす．

$1 \leq N \leq 20 000$

$1 \leq M \leq 1 000$

$0 \leq K \leq 1 000 000 000$

$1 \leq A_i \leq 1 000 000 000$ $(1 \leq i \leq N)$

$M \leq N$

入出力例

入力例1

6 3 6
1
2
3
1
2
1

出力例1

21

$1$ 番目の箱にオレンジ $1$ からオレンジ $3$ までの $3$ 個のオレンジを詰め，$2$ 番目の箱にオレンジ $4$ からオレンジ $6$ までの $3$ 個のオレンジを詰めると，箱詰めにかかるコストの総和は $(6+3 \times (3 - 1))+(6+3 \times (2 - 1)) = 21$ となる．

どのように詰めても箱詰めにかかるコストの総和が $21$ を下回ることはないので， $21$ を出力する．

入力例2

16 4 12
3
10
13
10
19
9
12
16
11
2
19
9
13
2
13
19

出力例2

164

$11$ 個の箱を用意して，それぞれの箱に前から順に $1$ 個，$3$ 個，$1$ 個，$1$ 個，$3$ 個，$1$ 個，$1$ 個，$2$ 個，$1$ 個，$1$ 個，$1$ 個のオレンジを詰めることで，箱詰めにかかるコストの総和が最小となる．

入力例3

16 6 14
19
7
2
15
17
7
14
12
3
14
5
10
17
20
19
12

出力例3

177

入力例4

10 1 1000000000
1
1
1
1
1
1
1
1
1
1

出力例4

10000000000

答えが32 ビット符号付き整数の範囲に収まるとは限らないことに注意せよ．

第15回 日本情報オリンピック本選 課題   2016 年 2 月 14 日

Solution in C++11 (judge verdict: Time Limit Exceeded)

#include<iostream>
#include<algorithm>
#include<vector>
#include<climits>
#include<cassert>
#include<cstring>

#define REP(i,s,n) for(int i=s;i<n;++i)
#define rep(i,n) REP(i,0,n)

using namespace std;

typedef long long ll;
const int IINF = INT_MAX;

class RMQ{
private:
  int limit,N;
  vector<int> dat;
public:
  void init(int n_){
    N = n_;
    limit = 1;
    while(limit<n_)limit*=2;
    dat.clear();
    dat.resize(2*limit,-IINF);
  }
  
  int _build(int cur,int L,int R,const vector<int> &buf){
    if( !( 0 <= cur && cur < 2*limit ) ) return -IINF;
    if( L == R-1 ) {
      if( L >= N ) return -IINF;
      dat[cur] = buf[L];
    } else {
      int vl = _build(cur*2+1,L,(L+R)/2,buf);
      int vr = _build(cur*2+2,(L+R)/2,R,buf);
      dat[cur] = max(vl,vr);
    }
    return dat[cur];
  }

  void build(const vector<int> &buf){ _build(0,0,limit,buf); };

  void update(int k,int a){
    k += limit-1;
    dat[k] = a;
    while(k > 0){
      k = (k-1)/2;
      dat[k] = max(dat[k*2+1],dat[k*2+2]);
    }
  }
 
  int _query(int a,int b,int k,int l,int r){
    if(r<=a || b<=l)return -IINF;
    else if(a<=l && r<=b)return dat[k];
    int vl = _query(a,b,k*2+1,l,(l+r)/2);
    int vr = _query(a,b,k*2+2,(l+r)/2,r);
    return max(vl,vr);
  }

  int query(int a,int b){ return _query(a,b,0,0,limit); }
};

class RRMQ{
private:
  int limit,N;
  vector<int> dat;
public:
  void init(int n_){
    N = n_;
    limit = 1;
    while(limit<n_)limit*=2;
    dat.clear();
    dat.resize(2*limit,IINF);
  }
  
  int _build(int cur,int L,int R,const vector<int> &buf){
    if( !( 0 <= cur && cur < 2*limit ) ) return IINF;
    if( L == R-1 ) {
      if( L >= N ) return IINF;
      dat[cur] = buf[L];
    } else {
      int vl = _build(cur*2+1,L,(L+R)/2,buf);
      int vr = _build(cur*2+2,(L+R)/2,R,buf);
      dat[cur] = min(vl,vr);
    }
    return dat[cur];
  }

  void build(const vector<int> &buf){ _build(0,0,limit,buf); };

  void update(int k,int a){
    k += limit-1;
    dat[k] = a;
    while(k > 0){
      k = (k-1)/2;
      dat[k] = min(dat[k*2+1],dat[k*2+2]);
    }
  }
 
  int _query(int a,int b,int k,int l,int r){
    if(r<=a || b<=l)return IINF;
    else if(a<=l && r<=b)return dat[k];
    int vl = _query(a,b,k*2+1,l,(l+r)/2);
    int vr = _query(a,b,k*2+2,(l+r)/2,r);
    return min(vl,vr);
  }

  int query(int a,int b){ return _query(a,b,0,0,limit); }
};

#define MAX 20010

ll dp[MAX];
int N,M;
ll K,A[MAX];

void computer() {
  RMQ maxt; RRMQ mint;
  {
    maxt.init(N);
    mint.init(N);
    vector<int> vec(N);
    rep(i,N) vec[i] = A[i];
    maxt.build(vec);
    mint.build(vec);
  }
  rep(i,N+1) dp[i] = LLONG_MAX;
  rep(i,N) {
    dp[i] = ((i-1>=0)?dp[i-1]:0) + K;
    for(int j=i-1;j>=0;--j) {
      if( i - j + 1 > M ) break;
      ll maxi = maxt.query(j,i+1);
      ll mini = mint.query(j,i+1);
      dp[i] = min(dp[i],((j-1>=0)?dp[j-1]:0)+K+(ll)(i-j+1) * ( maxi - mini ));
    }
  }
  cout << dp[N-1] << endl;
}

int main() {
  cin >> N >> M >> K;
  rep(i,N) cin >> A[i];
  computer();
  return 0;
}