码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForces - 1301E Nanosoft (dp+二维RMQ+二分)

时间:2020-02-29 22:38:09      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:++i   区域   scanf   题目   for   pre   代码量   rmq   logo   

题目链接

先dp求出以每个红色区域右下角为中心的能成为logo的最大半径

然后二维RMQ预处理,之后可O(1)询问任意子矩形中的最大值

最后对于每个询问二分最大logo的半径mid,这样问题就转化成判定是否存在半径大于等于mid的logo,在(x1+mid-1,y1+mid-1,x2-mid,y2-mid)的范围内找最大值判断是否大于等于mid即可

复杂度$O(nmlognlogm+qlog(min(n,m)))$

第一次写二维RMQ的题,感觉有点类似于树套树,代码量略小于树套树,但容易写挫

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=500+10,mod=1e9+7,inf=0x3f3f3f3f;
 5 int n,m,Q,a[N][N],b[N][N],c[N][N],d[4][N][N],r[N][N],ST[N][12][N][12],Log[N];
 6 char s[N][N];
 7 void buildy(int i,int k) {
 8     for(int j=1; j<=m; ++j)
 9         ST[i][k][j][0]=k==0?r[i][j]:max(ST[i][k-1][j][0],ST[i+(1<<(k-1))][k-1][j][0]);
10     for(int l=1; l<=Log[m]; ++l)
11         for(int j=1; j+(1<<l)-1<=m; ++j)
12             ST[i][k][j][l]=max(ST[i][k][j][l-1],ST[i][k][j+(1<<(l-1))][l-1]);
13 }
14 void build() {
15     for(int i=1; i<=n; ++i)buildy(i,0);
16     for(int k=1; k<=Log[n]; ++k)
17         for(int i=1; i+(1<<k)-1<=n; ++i)buildy(i,k);
18 }
19 int qry(int x1,int y1,int x2,int y2) {
20     int k=Log[x2-x1+1],l=Log[y2-y1+1];
21     return max(max(ST[x1][k][y1][l],ST[x1][k][y2-(1<<l)+1][l]),max(ST[x2-(1<<k)+1][k][y1][l],ST[x2-(1<<k)+1][k][y2-(1<<l)+1][l]));
22 }
23 int qry2(int x1,int y1,int x2,int y2) {
24     int ret=0;
25     int l=1,r=min((x2-x1+1)/2,(y2-y1+1)/2);
26     while(l<=r) {
27         int mid=(l+r)>>1;
28         if(qry(x1+mid-1,y1+mid-1,x2-mid,y2-mid)>=mid)ret=mid,l=mid+1;
29         else r=mid-1;
30     }
31     return ret*ret*4;
32 }
33 int main() {
34     Log[0]=-1;
35     for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1;
36     scanf("%d%d%d",&n,&m,&Q);
37     for(int i=1; i<=n; ++i)scanf("%s",s[i]+1);
38     for(int i=1; i<=n; ++i)
39         for(int j=1; j<=m; ++j) {
40             a[i][j]=(s[i][j]==R);
41             b[i][j]=(a[i][j]?b[i-1][j]+1:0);
42             c[i][j]=(a[i][j]?c[i][j-1]+1:0);
43             d[0][i][j]=min(min(b[i][j],c[i][j]),d[0][i-1][j-1]+1);
44         }
45     for(int i=1; i<=n; ++i)
46         for(int j=m; j>=1; --j) {
47             a[i][j]=(s[i][j]==G);
48             b[i][j]=(a[i][j]?b[i-1][j]+1:0);
49             c[i][j]=(a[i][j]?c[i][j+1]+1:0);
50             d[1][i][j]=min(min(b[i][j],c[i][j]),d[1][i-1][j+1]+1);
51         }
52     for(int i=n; i>=1; --i)
53         for(int j=1; j<=m; ++j) {
54             a[i][j]=(s[i][j]==Y);
55             b[i][j]=(a[i][j]?b[i+1][j]+1:0);
56             c[i][j]=(a[i][j]?c[i][j-1]+1:0);
57             d[2][i][j]=min(min(b[i][j],c[i][j]),d[2][i+1][j-1]+1);
58         }
59     for(int i=n; i>=1; --i)
60         for(int j=m; j>=1; --j) {
61             a[i][j]=(s[i][j]==B);
62             b[i][j]=(a[i][j]?b[i+1][j]+1:0);
63             c[i][j]=(a[i][j]?c[i][j+1]+1:0);
64             d[3][i][j]=min(min(b[i][j],c[i][j]),d[3][i+1][j+1]+1);
65         }
66     for(int i=1; i<=n; ++i)
67         for(int j=1; j<=m; ++j)
68             r[i][j]=min(min(d[0][i][j],d[1][i][j+1]),min(d[2][i+1][j],d[3][i+1][j+1]));
69     build();
70     while(Q--) {
71         int x1,y1,x2,y2;
72         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
73         printf("%d\n",qry2(x1,y1,x2,y2));
74     }
75     return 0;
76 }

 

CodeForces - 1301E Nanosoft (dp+二维RMQ+二分)

标签:++i   区域   scanf   题目   for   pre   代码量   rmq   logo   

原文地址:https://www.cnblogs.com/asdfsag/p/12386306.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!