E. Nanosoft (预处理, 三维dp)
Posted willems
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了E. Nanosoft (预处理, 三维dp)相关的知识,希望对你有一定的参考价值。
题目: 传送门
题意:
定义Nanosoft的 logo 为 四个大小相同的正方形合并成一个大正方形。左上角是红色的,右上角是绿色的,左下角是黄色的,右下角是蓝色的。
例如以下这些都是
以下这些都不是
给你一个n * m的矩阵,这个矩阵由 4 个大写字母 “R” , "G", “Y”, “B” 构成,这四个大写字母分别代表红色,绿色,黄色,蓝色。
有Q次询问,每次询问, 输入两个坐标,(x1, y1), (x2, y2) 代表 以 (x1, y1) 为矩阵左上角的坐标,(x2, y2)为矩阵右下角的坐标的矩阵中,能作为Nanosoft的 logo的 子矩阵面积最大是多少。
题解:
首先,定义 pre[ i ][ j ][ col ] 代表矩阵 (1, 1) , (i, j) 中 颜色为 col 的格有多少个, 也就是二维前缀和, 这个可以很简单预处理出来。
显然, 能作为Nanosoft的 logo 的都必须是正方形, 且边长必须是偶数。
然后定义 dp[ i ][ j ][ k ] 为 以(i, j) 为右下角, 边长为 k 的正方形中, 能作为Nanosoft的logo的子正方形的边长的最大值, 也就是以 (i - k + 1, j - k + 1) 为左上角, (i, j)为右下角的正方形中,能作为Nanosoft的 logo的子正方形边长的最大值。
转移方程就是: dp[ i ][ j ][ k ] = max({ dp[ i ][ j ][ k ], dp[ i ][ j ][k - 1], dp[i - 1][ j ][k - 1], dp[ i ][j - 1][k - 1], dp[i - 1][j - 1][k - 1] });
我们还可以在o(1)的时间里判断 以 (i,j)为右下角坐标,边长为 k 的正方形是否能整个作为Nanosoft的 logo,能的话,那dp[ i ][ j ][ k ] 就是 k 了。
然后对于每个询问, 我们知道, 最大的正方形的边长就是 min(x2 - x1 + 1, y2 - y1 + 1);
那我们可以枚举这样的正方形。 最多每次询问都枚举 max(n, m) 次, 那复杂度就是 n * q 不至于超时。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX #define PI acos(-1) using namespace std; const int N = 510; char a[N][N]; char s[] = "RGYB"; int n, m, q; int pre[N][N][4]; ///第三维,0代表红色,1代表绿色,2代表黄色,3代表蓝色 int dp[N][N][N]; int check(int lux, int luy, int rdx, int rdy, int col) { return pre[rdx][rdy][col] - pre[rdx][luy - 1][col] - pre[lux - 1][rdy][col] + pre[lux - 1][luy - 1][col]; } void init() { rep(k, 0, 3) rep(i, 1, n) rep(j, 1, m) pre[i][j][k] = pre[i - 1][j][k] + pre[i][j - 1][k] - pre[i - 1][j - 1][k] + (a[i][j] == s[k]); rep(i, 1, n) rep(j, 1, m) { for(int k = 1; k <= min(i, j); k++) { if(k % 2 == 0) { int len = k / 2; if(check(i - len + 1, j - len + 1, i, j, 3) == len * len &&check(i - len + 1, j - k + 1, i, j - len, 2) == len * len &&check(i - k + 1, j - len + 1, i - len, j, 1) == len * len &&check(i - k + 1, j - k + 1, i - len, j - len, 0) == len * len) dp[i][j][k] = k; } dp[i][j][k] = max({ dp[i][j][k], dp[i][j][k - 1], dp[i - 1][j][k - 1], dp[i][j - 1][k - 1], dp[i - 1][j - 1][k - 1] }); } } } int main() { scanf("%d %d %d", &n, &m, &q); rep(i, 1, n) scanf("%s", a[i] + 1); init(); while(q--) { int x1, x2, y1, y2; scanf("%d %d %d %d", &x1, &y1, &x2, &y2); int len = min(x2 - x1 + 1, y2 - y1 + 1); int ans = 0; if(x2 - x1 > y2 - y1) { int dis = (x2 - x1) - (y2 - y1); rep(i, 0, dis) ans = max(ans, dp[x2 - i][y2][len]); } else { int dis = (y2 - y1) - (x2 - x1); rep(i, 0, dis) ans = max(ans, dp[x2][y2 - i][len]); } printf("%d ", ans * ans); } return 0; }
以上是关于E. Nanosoft (预处理, 三维dp)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces1539 E. Game with Cards(思维+dp,st表倍增+二分 预处理)
Codeforces Round #455 (Div. 2) E. Coprocessor DAG图上dp