我们知道子一行也是矩阵,只不过是特殊情况,首先来一道题,hdu 1506
高度h[i] 我们定义两个数组,分别为向左扩展能到的最左边的下标,和向右扩展能到的最右边的下标。
然后两个数组分别从正方向和反反向扫一遍
#include<cstdio> #include<cstring> using namespace std; #define LL long long LL num[100005]; LL l[100005],r[100005]; int main() { int n; LL ans; for(;scanf("%d",&n),n;) { for(int i=1;i<=n;++i) scanf("%I64d",&num[i]); num[0]=num[n+1]=-1; for(int i=1;i<=n;++i) l[i]=r[i]=i; //dp,根据之前拓展的l,r再拓展,可以提高效率 for(int i=1;i<=n;++i) //第i个高度拓展,h[j]>=h[i]的最小j for(;num[l[i]-1]>=num[i];) l[i]=l[l[i]-1]; for(int i=n;i>=1;--i) //第i个高度拓展,h[j]>=h[i]的最大j for(;num[r[i]+1]>=num[i];) r[i]=r[r[i]+1]; ans=0; for(int i=1;i<=n;++i) if(ans<num[i]*(r[i]-l[i]+1)) ans=num[i]*(r[i]-l[i]+1); printf("%I64d\n",ans); } return 0; }
现在特殊情况考虑完了以后,我们考虑正常矩阵
hdu 1505
这次定义一个Up数组从上往下扫描,相当于矩阵的压缩,于是每次只要对一行的Up进行处理,相当于就转换成了第一个问题特殊情况:一行的矩阵
#include<iostream> #include<stdio.h> #include<algorithm> #include<math.h> #include<ctype.h> using namespace std; #define oo 0x3f3f3f3f #define maxn 1010 int Up[maxn][maxn]; int L[maxn], R[maxn]; char map[maxn][maxn]; int main() { int T, n, m, ans; char val[5]; scanf("%d", &T); while (T--) { scanf("%d %d", &n, &m); for (int i = 1; i <= m; i++) Up[0][i] = 0; for (int i = 1; i <= n;i++) for (int j = 1; j <= m; j++) { scanf("%s", &val); if (val[0] == 'F') Up[i][j] = Up[i - 1][j] + 1; else Up[i][j] = 0; } ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) L[j] = R[j] = j; Up[i][0] = Up[i][m + 1] = -1; for (int j = 2; j <= m; j++) while (Up[i][L[j] - 1] >= Up[i][j]) L[j] = L[L[j] - 1]; for (int j = m - 1; j >= 1;j--) while (Up[i][R[j] + 1] >= Up[i][j]) R[j] = R[R[j] + 1]; for (int j = 1; j <= m; j++) ans = max(ans, Up[i][j] * (R[j] - L[j] + 1)); } printf("%d\n", ans * 3); } return 0; } /* 1.00 3.71 0.04 5.19 0.00 */在以上基础加条件的
hdu 2870 题目加点要求就是允许将某个字母变成某个字母
这样只要将字母变成对应的字母,然后对每种变换进行一次dp,找到其中最大的值,其实情况只要3三种就ok了,贪心思想:尽量让所有的字母变成a,b,c这样只要对a,b,c的情况dp就ok了。
#include<iostream> #include<stdio.h> #include<algorithm> #include<math.h> #include<ctype.h> using namespace std; #define oo 0x3f3f3f3f #define maxn 1010 int Up[maxn][maxn]; int L[maxn], R[maxn]; char map[maxn][maxn]; bool ok[4][30]; void Solve() { memset(ok, 0, sizeof ok); ok[0]['a' - 'a'] = 1; ok[0]['w' - 'a'] = 1; ok[0]['y' - 'a'] = 1; ok[0]['z' - 'a'] = 1; ok[1]['w' - 'a'] = 1; ok[1]['x' - 'a'] = 1; ok[1]['z' - 'a'] = 1; ok[1]['b' - 'a'] = 1; ok[2]['x' - 'a'] = 1; ok[2]['y' - 'a'] = 1; ok[2]['z' - 'a'] = 1; ok[2]['c' - 'a'] = 1; } int main() { Solve(); int n, m, ans; while (scanf("%d %d", &n, &m) != EOF) { for (int i = 1; i <= m; i++) Up[0][i] = 0; for (int i = 1; i <= n; i++) scanf("%s", map[i] + 1); ans = 0; for (int k = 0; k < 3; k++) { for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (ok[k][map[i][j] - 'a']) Up[i][j] = Up[i - 1][j] + 1; else Up[i][j] = 0; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) L[j] = R[j] = j; Up[i][0] = Up[i][m + 1] = -1; for (int j = 2; j <= m; j++) while (Up[i][L[j] - 1] >= Up[i][j]) L[j] = L[L[j] - 1]; for (int j = m - 1; j >= 1; j--) while (Up[i][R[j] + 1] >= Up[i][j]) R[j] = R[R[j] + 1]; for (int j = 1; j <= m; j++) ans = max(ans, Up[i][j] * (R[j] - L[j] + 1)); } } printf("%d\n", ans); } return 0; } /* 1.00 3.71 0.04 5.19 0.00 */现在稍微再改变下
hdu 2830 题目要求可以交换任意列任意次,一开没想到怎么做,看了题解发现,只要对每次的行进行列的排序,然后枚举列大到小的长度,这样就可以找出最大的值。
#include<iostream> #include<stdio.h> #include<algorithm> #include<math.h> #include<ctype.h> using namespace std; #define oo 0x3f3f3f3f #define maxn 1010 int up[2][maxn]; int res[maxn]; char map[2][maxn]; int main() { int n, m, ans; while (scanf("%d %d", &n, &m) != EOF) { memset(up, 0, sizeof up); ans = 0; for (int i = 1; i <= n; i++) { scanf("%s", map[i % 2] + 1); for (int j = 1; j <= m; j++) { if (map[i % 2][j] == '1') up[i % 2][j] = up[(i - 1) % 2][j] + 1; else up[i % 2][j] = 0; } memcpy(res, up[i % 2], sizeof res); sort(res + 1, res + 1 + m); for (int j = 1; j <= m; j++) ans = max(ans, (m - j + 1)*res[j]); } printf("%d\n", ans); } return 0; } /* 1.00 3.71 0.04 5.19 0.00 */