C.Alyona and Spreadsheet
题意:
1.给你一个
n×m
的矩阵。
2.
k
次询问。每次给定两个边界
3.数据范围:
思路1:
1.每一列用数组
dp[i]
表示第
i
行至多到
2.每统计好一列,用数组
to[i]
来维护
dp[i]
的最大值。
3.当
dp[i−1]≥i
时,
dp[i]=dp[i−1]
4.最终判断条件:
to[l]≥r
是满足条件。
代码1:
#include <bits/stdc++.h>
using namespace std;
vector<int>mp[100100];
int dp[100100]; //每一列的tmp值,表示第i行至多到dp[i]行是不递减的
int to[100100]; //维护dp[i]的最大值
int main() {
int n, m, x;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) {
mp[i].resize(m + 1);
for (int j = 1; j <= m; ++ j) {
scanf("%d", &mp[i][j]);
}
}
for (int i = 1; i <= n; ++ i) to[i] = i;
for (int j = 1; j <= m; ++ j) {
for (int i = 1; i <= n; ++ i) dp[i] = i;
//第1行
for (int i = 2; i <= n; ++ i) {
if(mp[i][j] >= mp[i-1][j])
dp[1] = i;
else
break;
}
//第2行到第n行
for (int i = 2; i <= n; ++ i) {
//因为这一步,所以总的复杂度是O(nm)
if (dp[i-1] >= i) {
dp[i] = dp[i-1];
continue;
}
for (int k = i + 1; k <= n; ++ k) {
if(mp[k][j] >= mp[k-1][j])
dp[i] = k;
else
break;
}
}
//每统计一列,更新一下to
for (int i = 1; i <= n; ++ i)
to[i] = max(to[i], dp[i]);
}
int k, l, h;
scanf("%d", &k);
while(k--) {
scanf("%d%d", &l, &h);
if(to[l] >= h) puts("Yes");
else puts("No");
}
}
思路2:
1.用数组
dp[i]
表示这一列到第
i
行时是长度为
2.如果第
i
行数字大于等于第
3.最终判断条件:
代码2:
//优雅一点的dp
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000;
vector<int>mp[maxn + 5];
int dp[maxn + 5]; //表示在一列中,到第i行时,最大不递减长度为dp[i]
int len[maxn + 5];//表示最终到第i行时,最大不递减长度为len[i]
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) {
mp[i].resize(m + 1);
for (int j = 1; j <= m; ++ j)
scanf("%d", &mp[i][j]);
}
fill(len + 1, len + 1 + n, 1); //初始化
for (int i = 1; i <= m; ++ i) {
dp[1] = 1;
for (int j = 2; j <= n; ++ j) {
//如果当前行的值大于上一行,那么迭代dp结果,否则为1
dp[j] = (mp[j][i] >= mp[j - 1][i] ? dp[j - 1] + 1: 1);
len[j] = max(len[j], dp[j]);
}
}
int k, l, r;
scanf("%d", &k);
while (k--) {
scanf("%d%d", &l, &r);
if (len[r] >= r - l + 1) puts("Yes");
else puts("No");
}
}