[HAOI2007]理想的正方形 - 洛谷https://www.luogu.com.cn/problem/P2216首先这一题我们可以压缩矩阵,用单调队列维护行和列
先维护每一行区间最大值和最小值
再维护更新后的数组的每一列的最大值和最小值
最后得出的数组的每一个元素就是n*n矩阵的元素的最大值和最小值,画图就可以明白了、
int s[1005][1005];
int X[1005][1005], x[1005][1005];
int Y[1005][1005], y[1005][1005];
//int q1[MAXN];
//int q2[MAXN];
int main() {
deque<int> q1, q2;
int a, b, n;
scanf("%d %d %d", &a, &b, &n);
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= b; j++) {
scanf("%d", &s[i][j]);
}
}
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= b; j++) {
if (!q1.empty() && j - q1.front() >= n)
q1.pop_front();
if (!q2.empty() && j - q2.front() >= n)
q2.pop_front();
while (!q1.empty() && s[i][q1.back()] < s[i][j]) {
q1.pop_back();
}
while (!q2.empty() && s[i][q2.back()] > s[i][j]) {
q2.pop_back();
}
q1.push_back(j);
q2.push_back(j);
if (j >= n) {
X[i][j - n + 1] = s[i][q1.front()];
x[i][j - n + 1] = s[i][q2.front()];
}
}
q1.clear();
q2.clear();
}
for (int i = 1; i <= b - n + 1; i++) {
for (int j = 1; j <= a; j++) {
if (!q1.empty() && j - q1.front() >= n)
q1.pop_front();
if (!q2.empty() && j - q2.front() >= n)
q2.pop_front();
while (!q1.empty() && X[q1.back()][i] < X[j][i])
q1.pop_back();
while (!q2.empty() && x[q2.back()][i] > x[j][i])
q2.pop_back();
q1.push_back(j);
q2.push_back(j);
if (j >= n) {
Y[j - n + 1][i] = X[q1.front()][i];
y[j - n + 1][i] = x[q2.front()][i];
}
}
q1.clear();
q2.clear();
}
int ans = INF;
for (int i = 1; i <= a - n + 1; i++) {
for (int j = 1; j <= b - n + 1; j++) {
ans = min(ans, Y[i][j] - y[i][j]);
}
}
printf("%d", ans);
return 0;
}
选择数字 - 洛谷https://www.luogu.com.cn/problem/P2034这一题属于单调队列优化的dp
题目要求我们求取若干数,但不连续取k个以上的数后的最大和。我们可以将问题转换为删除若干数,且删除数的间隔最多为k,求删除数的最小和。
所以我们易得
dp[i]=a[i] i<=k+1;
dp[i]=min dp[j]+ a[i] i>k+1
维护第二个递推式时我们需要用到单调队列维护,维护k+1区间的dp的最小值;
int n, k;
ll a[MAXN];
ll dp[MAXN];
int main() {
scanf("%d %d", &n, &k);
ll sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", a + i);
sum += a[i];
}
deque<int> q;
for (int i = 1; i <= n; i++) {
if (i <= k + 1)
dp[i] = a[i];
else
dp[i] = dp[q.front()] + a[i];
if (!q.empty() && i - q.front() >= k + 1)
q.pop_front();
while (!q.empty() && dp[q.back()] > dp[i])
q.pop_back();
q.push_back(i);
}
printf("%lld\n", sum - *min_element(dp + n - k, dp + n + 1));
return 0;
}