公式

I - Shipping 解説 by en_translator


Since \(T_N \le 10^{12}\) (the calendar is huge), we cannot get the correct answer by naively managing daily transitions.
How can we reduce the days to inspect?

In fact, days of shipment can be limited to:

  • day \(T_i + kX\),
    • where \(1 \le i \le N\) and \(0 \le k \le N\).

Brief proof:
For orders \(i\) and \(j\) (\(i < j\)), shipping \(j\) before \(i\) does not reduce the dissatisfaction (there is an optimal solution that ships the orders in … er, in order).
Then, for a set of orders to be shipped simultaneously, one of the following two always happens:

  • they are shipped when the last one is ready;
  • \(X\) days after the last shipment, all the orders are ready, so ship them immediately on that day.

The former can be represented as day \(T_i\) for some \(i\), and the latter as \(X\) days after a shipment; thus we arrive at the conclusion above.

Now the number of days to inspect has been reduced to \(O(N^2)\).

Now the problem can be solved by the following DP (Dynamic Programming).

Let us call the days to focus as event \(1,2,\dots\).

\(dp\)[ event \(i\) ][ order \(j\) was shipped last time ] = { the minimum total dissatisfaction \(x\) for the orders shipped so far }.

The transitions are as follows:

  • transition \(x\) onto \(dp[i+1][j]\) (doing nothing on the day of event \(i\))
  • let \(d\) be the next event on or after \(X\) days past event \(i\). Then, transition \(x\) + ( the total dissatisfaction when shipping orders \(j+1\) through \(j+m\) on the day of event \(i\) ) onto \(dp[d][j+m]\).

This DP works in \(O(N^3K)\) time. Since the execution time limit is set abundantly, a solution with one more factor may still pass if the constant factor is light enough.

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;

int main(){
  long long n,k,x;
  cin >> n >> k >> x;
  vector<long long> t(n);
  for(auto &nx : t){cin >> nx;}

  vector<long long> clk;
  for(long long i=0;i<n;i++){
    for(long long j=0;j<=n;j++){
      clk.push_back(t[i]+j*x);
    }
  }

  sort(clk.begin(), clk.end());
  clk.erase(unique(clk.begin(),clk.end()),clk.end());

  long long cs=clk.size();
  vector<vector<long long>> dp(cs+1,vector<long long>(n,8e18));
  dp[0][0]=0;
  long long res=8e18;
  long long nxt=0;
  for(long long i=0;i<cs;i++){
    while(nxt<cs && clk[nxt]<clk[i]+x){nxt++;}

    for(long long j=0;j<n;j++){
      if(dp[i][j]>4e18){continue;}
      dp[i+1][j]=min(dp[i+1][j],dp[i][j]);

      long long mv=dp[i][j];
      for(long long m=j;m<min(j+k,n);m++){
        if(clk[i]<t[m]){break;}

        mv+=(clk[i]-t[m]);

        if(m==n-1){
          // finish
          res=min(res,mv);
        }
        else if(nxt<cs){
          dp[nxt][m+1]=min(dp[nxt][m+1],mv);
        }
      }
    }
  }

  cout << res << "\n";
  return 0;
}

投稿日時:
最終更新: