CF1301E-Nanosoft 思维 棋盘DP

这道题最初的想法是,所有的合法图案都由中间的那个核心的四个格子扩展而成,所以想把核心找出来,用数据结构维护,每次找出询问范围内可以扩展最大的核心。

仔细想想这样子可能会涉及到二维的数据结构,可能的复杂度也过高,有些想骗了。

考虑DP,dp[i][j][k]表示,以i,j为右下角,边长为k的正方形中,最大的合法标志大小。

转移,dp[i][j][k] = max(dp[i][j][k - 1],max(dp[i - 1][j][k - 1],max(dp[i][j - 1][k - 1],dp[i - 1][j - 1][k - 1])));

然后考虑i,j带来的影响,只可能是以i,j为右下角构成了边长为k的合法标志,这个我们分颜色二维前缀和判断就可以了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 int n,m,q,sum[4][510][510],dp[510][510][510],res;
 5 char mp[510][510];
 6 int c2n(char c)
 7 {
 8     if (c == 'R')
 9         return 0;
10     if (c == 'G')
11         return 1;
12     if (c == 'Y')
13         return 2;
14     if (c == 'B')
15         return 3;
16     return -1;
17 }
18 bool check(int x,int y,int l)
19 {
20     if (sum[3][x][y] - sum[3][x - l / 2][y] - sum[3][x][y - l / 2] + sum[3][x - l / 2][y - l / 2] != l * l / 4)
21         return false;
22     if (sum[2][x][y - l / 2] - sum[2][x][y - l] - sum[2][x - l / 2][y - l / 2] + sum[2][x - l / 2][y - l] != l * l / 4)
23         return false;
24     if (sum[1][x - l / 2][y] - sum[1][x - l][y] - sum[1][x - l / 2][y - l / 2] + sum[1][x - l][y - l / 2] != l * l / 4)
25         return false;
26     if (sum[0][x - l / 2][y - l / 2] - sum[0][x - l][y - l / 2] - sum[0][x - l / 2][y - l] + sum[0][x - l][y - l] != l * l / 4)
27         return false;
28     return true;
29 }
30 int main()
31 {
32     scanf("%d%d%d",&n,&m,&q);
33     for (int i = 1;i <= n;i++)
34         scanf("%s",mp[i] + 1);
35     for (int i = 1;i <= n;i++)
36         for (int j = 1;j <= m;j++)
37         {
38             for (int o = 0;o <= 3;o++)
39                 sum[o][i][j] = sum[o][i - 1][j] + sum[o][i][j - 1] - sum[o][i - 1][j - 1];
40             sum[c2n(mp[i][j])][i][j]++;
41         }
42     for (int i = 1;i <= n;i++)
43         for (int j = 1;j <= m;j++)
44             for (int k = 1;k <= min(i,j);k++)
45             {
46                 dp[i][j][k] = max(dp[i][j][k - 1],max(dp[i - 1][j][k - 1],max(dp[i][j - 1][k - 1],dp[i - 1][j - 1][k - 1])));
47                 if (!(k & 1) && check(i,j,k))
48                     dp[i][j][k] = k;
49             }
50     int r1,c1,r2,c2;
51     for (int i = 1;i <= q;i++)
52     {
53         res = 0;
54         scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
55         int k = min(r2 - r1 + 1,c2 - c1 + 1);
56         if (r2 - r1 > c2 - c1)
57         {
58             for (int o = r2;o - k + 1 >= r1;o--)
59             {
60                 res = max(res,dp[o][c2][k]);
61             }
62         }else
63         {
64             for (int o = c2;o - k + 1 >= c1;o--)
65             {
66                 res = max(res,dp[r2][o][k]);
67             }
68         }
69         printf("%d\n",res * res);
70     }
71     return 0;
72 }

猜你喜欢

转载自www.cnblogs.com/iat14/p/12315694.html