---
# System prepended metadata

title: 'Để dễ hình dung hơn, với mỗi t'

---

Để dễ hình dung hơn, với mỗi truy vấn có các tham số $s,f,c,r$, ta sẽ hiểu là cần xây dựng một dãy $a_{p_1}, a_{p_2}, a_{p_3}, ... ,a_{p_{r+1}}$, với dãy $p$ không giảm và $p_1 = s$ và $p_{r+1} = f$, sao cho $val = max (a_{p_i}-a_{p_{i-1}})$ là bé nhất.

Kết quả của truy vấn sẽ chính là $val*c$. Như vậy kết quả của bài toán sẽ là $max(val*c)$ với mọi truy vấn.
# Subtask 1
- Ta sẽ dùng phương pháp chặt nhị phân kết quả để tìm giá trị $val$ .
- Với mỗi giá trị $mid$, ta có thể kiểm tra xem nó có thỏa mãn không bằng cách xuất phát từ $a_s$, đi đến một vị trí $i$ sao cho $i$ lớn nhất, $i > s$ và $a_i - a_s \le mid$. Ta tính đây là một lần **dừng lại**. Sau đó, ta lại xuất phát từ $i$ và lặp lại hành động tương tự. Nếu ta có thể đi tới được $f$ mà không cần **dừng lại** quá $r$ lần, giá trị $mid$ sẽ thỏa mãn.
- Như vậy, ta có thể chặt nhị phân để tìm $val$ nhỏ nhất thỏa mãn.
- Độ phức tạp $O(n*log)$ cho **một** truy vấn.

# Subtask 3
- Tuy lần này, $n \le 400$, nhưng $m$ lại rất lớn, lên tới $5*10^5$ nên một thuật toán như $subtask$ $1$ sẽ không thể chạy.
- Ta cần sử dụng kĩ thuật quy hoạch động cho bài toán này. Gọi $dp(l,r,k)$ là kết quả tối ưu (giá trị $val$) cho đoạn $[l,r]$ nếu ta chỉ được dừng lại $k$ lần. Như vậy, với mỗi truy vấn ta sẽ lấy kết quả với $max (c*dp(s,f,r))$.
- Ta có công thức quy hoạch động như sau: $dp(l,r,k) = min(max(dp(l,x,k-1),a[r]-a[x]))$, với $x \in [l,r-1]$.
- Như vậy ta sẽ thu về thuật toán có độ phức tạp $O(n^4)$, chỉ đủ để qua $subtask$ $2$.
- Đến đây ta cần tối ưu công thức này như sau:
    - Gọi $optimize(l,r,k) = x$ là vị trí tốt nhất mà $dp(l,r,k) = max (dp(l,x,k-1),a[r]-a[x])$ đạt $min$. 
    - Ta có nhận xét rằng $optimize(l,r,k) \le optimize(l,r+1,k)$.
    - Mặt khác, ta có $dp(l,r,k) = min (max (dp(l,x,k-1),a[r]-a[x]))$, mà $dp(l,x,k-1) \le dp (l,x+1,k-1)$, đồng thời $a[r] - a[x] > a[r] - a[x+1]$ và hàm $y = max (dp(l,x,k-1),a[r]-a[x])$ sẽ có dạng giảm dần xuống đáy với từng giá trị $x$ rồi sau khi chạm đáy giá trị sẽ tăng dần. Như vậy, ta chỉ cần tăng $x$ tới khi nào $max (dp(l,x,k-1),a[r]-a[x])$ chạm đáy.
    - Vậy ta có thể thực hiện thuật toán $2$ con trỏ để tính được mảng $optimize$ song song với việc tính mảng $dp$.
    - Từ đó ta thu được thuật toán $O(n^3)$.
- Tuy vậy, ta cần tối ưu hóa bộ nhớ, dễ thấy ta không cần lưu chiều $l$ của $dp(l,r,k)$, đồng thời không cần lưu mảng $optimize$. Từ đó bộ nhớ giảm xuống còn $N^2$.

Code:
```cpp
#include<iostream>
#include<vector>
using namespace std;
const int N = 405;
const int M = 1e5+5;
int d[N][N];
int n,m;
int a[M];
long long res = 0;
struct qr {
	int f,c,r;
};
vector<qr> v[N];
namespace sub1 {
	int s,f,c,r;
	bool check (int mid) {
		int res = 0;
		int st = s;
		for (int i=s; i<=f; i++) {
			int j = i;
			while (j < f && a[j+1]-a[i] <= mid) {
				j++;
			}
			if (j == i) return false;
			i = j-1;
			res++;
			if (j == f) break;
		} res--;
		return res <= r;
	}
	void solve () {
		for (int i=1; i<=n; i++) cin >> a[i];
		cin >> s >> f >> c >> r;
		long long lef = 0, rig = 1e9, res = 1e9;
		while (rig >= lef) {
			int mid = (rig+lef) >> 1;
			if (check(mid)) res = mid, rig = mid - 1;
			else lef = mid + 1;
		}
		cout << 1ll*res*c << '\n';
	}
}
void cal () {
	for (int l=1; l<=n; l++) {
		for (int r=l; r<=n; r++) {
			d[r][0] = a[r] - a[l];
		}
		for (int k=1; k<=n; k++) {
			int opt = l;
			for (int r=l; r<=n; r++) {
				while (opt < r && max (d[opt][k-1],a[r]-a[opt]) >= max (d[opt+1][k-1],a[r]-a[opt+1])) {
					opt++;
				}
				d[r][k] = max (d[opt][k-1],a[r]-a[opt]);
			}
		}
		for (auto val : v[l]) {
			int f = val.f, c = val.c, r = val.r;
			res = max (res,1ll*d[f][r]*c);
		}
	}
}
signed main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> m;
	if (m == 1) {
		sub1::solve();
		return 0;
	}
	for (int i=1; i<=n; i++) {
		cin >> a[i];
	}
	for (int i=1; i<=m; i++) {
		int s,f,c,r;
		cin >> s >> f >> c >> r;
		v[s].push_back({f,c,r});
	}
	cal();
	cout << res;
}
```