D - 道路の整備 / Road Maintenance Editorial
by
kyopro_friends
Editorial for printing
考察
必要条件
条件を満たす数列 \(A'\) が満たす条件を考えます。
三角不等式より任意の \(i<j\) に対して
\(|A'_i-A'_j| \leq \sum_{k=i}^{j-1}|A'_k-A_{k+1}|\leq (j-i)D\)
が成り立ちます。 よって特に \(A'_i \geq A'_j -(j-i)D \geq A_j -(j-i)D\) が成り立ちます。
同様に任意の \(j<i\) に対して \(A'_i \geq A_j -(i-j)D\) が成り立ちます。
これらを合わせ、 \(A'_i\geq \max_{1 \leq j \leq N}(A_j-|i-j|D)\) が必要条件であることがわかります。
十分条件
逆に \(A'_i=\max_{1 \leq j \leq N}(A_j-|i-j|D)\) と定めた数列 \(A'\) が条件を満たすことを示します。
三角不等式 \(|i-j|\leq |i+1-j|+|i-(i+1)|\) より
\(\begin{aligned} A'_i&=\max_{1 \leq j \leq N}(A_j-|i-j|D)\\ &\geq\max_{1 \leq j \leq N}(A_j-(|i+1-j|+1)D)\\ &\geq\max_{1 \leq j \leq N}(A_j-|i+1-j|D)+D\\ &=A'_{i+1}+D \end{aligned}\)
であり、\(i\) と \(i+1\) を入れ替えて同様の議論をすることで \(A'_{i+1}\geq A'_i+D\) を得るので、 \(|A'_i-A'_{i+1}|\leq D\) が成り立ちます。
また、こうして作られた数列は明らかにコスト最小です。
実装
\(A'_i=\max_{1 \leq j \leq N}(A_j-|i-j|D)\) を愚直に計算すると \(\Theta(N^2)\) になり、実行時間制限に間に合わせることは非常に困難です。
ここで、新たな数列 \(P_i=A_i+Di\)、 \(M_i=A_i-Di\) を用いると、\( A'_i=\max(-Di+\max_{j<i}P_j, Di+\max_{j>i}M_i)\) となることから、 \(P,M\) の累積 max を予め求めておくことで、 \(A'_i\) は各 \(i\) に対して \(O(1)\) で求めることができます。
全体の計算量は \(O(N)\) です。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
long long d;
cin >> n >> d;
vector<long long> a(n), c(n);
for(int i=0; i<n; i++) cin >> a[i];
for(int i=0; i<n; i++) cin >> c[i];
vector<long long> p(n), m(n);
for(int i=0; i<n; i++){
p[i] = a[i] + d*i;
m[i] = a[i] - d*i;
}
vector<long long> pmax(n);
pmax[0] = p[0];
for(int i=1; i<n; i++){
pmax[i] = max(pmax[i-1], p[i]);
}
vector<long long> mmax(n);
mmax[n-1] = m[n-1];
for(int i=n-2; i>=0; i--){
mmax[i] = max(mmax[i+1], m[i]);
}
vector<long long> aa(n);
for(int i=0; i<n; i++){
aa[i] = max(-d*i + pmax[i], d*i + mmax[i]);
}
long long ans = 0;
for(int i=0; i<n; i++){
ans += (aa[i]-a[i]) * c[i];
}
cout << ans << endl;
}
実装例 (Python)
N, D = map(int, input().split())
A = list(map(int, input().split()))
C = list(map(int, input().split()))
P = [A[i] + D*i for i in range(N)]
M = [A[i] - D*i for i in range(N)]
Pmax = [0] * N
Pmax[0] = P[0]
for i in range(1, N):
Pmax[i] = max(Pmax[i-1], P[i])
Mmax = [0] * N
Mmax[-1] = M[-1]
for i in range(1, N):
Mmax[~i] = max(Mmax[~i+1], M[~i])
AA = [max(-D*i + Pmax[i], D*i + Mmax[i]) for i in range(N)]
ans = sum((AA[i]-A[i]) * C[i] for i in range(N))
print(ans)
posted:
last update:
