标签:mes 运算 memset pre clu 逻辑运算 bit font code
(全英文题面所以直接放化简题意)
题意:在一个二维平面内,初始有一些点,然后每个时间点加入一些点,对每个时间点求平面内最大的无障碍正方形
(这次的题目是真的神仙啊。。。)
solution:
(以下初始思路来自老师)
这个正方形可能出现在哪里?
一个正方形由长和宽构成,要找最大边长,其实就是要维护两个东西:长和宽。
分别考虑长宽如何维护(好吧差不多都是边长)
宽:它可能经过一个点,也就是这个点在宽这条边上。
于是不太容易想到:维护两个dp数组,存每个点向左右能拓展的长度。
但是,如果依旧暴力更新,还是会炸成渣滓。。。
瞪大眼看题,当一个点更新时,只有它所在的一行会变,所以就可以O(n)更新dp数组了。
于是,只要在每个点加上后更新dp数组,然后查出最大正方形,就完事了
下面考虑列:
能不能像刚刚那样继续dp嘞?(像cdq那样dp套dp呢???)如果这样做,那可能会得到一个错位的正方形。。。很麻烦.....
况且我们要去最大的不是吗?这好像有什么提示.....
想想我学过的维护最值的数据结构(qsort rmq 线段树 单调队列 主席树 平衡树 树套树)
再结合一下问题实际:找长度,不太容易想到,对于每一个答案,进行一次check。这个check,有点像二分,对于每一个可行答案进行判断然后更新最优解。而这个可行答案,就是看是否能找到更大的正方形。
对此,只需要枚举是否能找到比当前更大的边长就行了。因为它是正方形,所以长宽相等,这里列问题就转化为了:
对于每一个定长区间,找最大的一个之前处理出的dp数组里是否有一个长度大于等于它的值,也就是最大值。
这就很明朗了,线段树,单调队列。
两者差距在哪里呢?线段树O(nlogn)单调队列O(n);
我用了单调队列。
这份代码给我的感觉就是:代码还可以继续化简,逻辑运算符可以有效增加效率和增加美观度
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=2050; char s[maxn]; int n,m,k; int a[maxn][maxn]; struct node { int x,y,res; }ans[maxn]; int f[maxn][maxn]; int l[maxn][maxn]; int r[maxn][maxn]; void init() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++) { a[i][j]=(s[j]==‘.‘); } } for(int i=1;i<=k;i++) { scanf("%d%d",&ans[i].x,&ans[i].y); a[ans[i].x][ans[i].y]=0; } } void dp() { for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { if(!a[i][j]) continue; if(i==1||j==m) { f[i][j]=1; ans[k].res=max(ans[k].res,1); continue; } f[i][j]=min(f[i-1][j],f[i][j+1]); if(a[i-f[i][j]][j+f[i][j]])f[i][j]++; ans[k].res=max(ans[k].res,f[i][j]); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { l[i][j]=a[i][j]*(l[i][j-1]+1); } } for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { r[i][j]=a[i][j]*(r[i][j+1]+1); } } } int tmp[maxn]; int q[maxn]; bool check(int x,int y) { int head=1,tail=0; memset(tmp,0,sizeof(tmp)); for(int i=1;i<=n;i++) { while(head<=tail&&l[q[tail]][y]>=l[i][y]) tail--; q[++tail]=i; while(q[head]<=i-x) head++; tmp[i]+=l[q[head]][y]; } head=1;tail=0; for(int i=1;i<=n;i++) { while(head<=tail&&r[q[tail]][y]>=r[i][y]) tail--; q[++tail]=i; while(q[head]<=i-x) head++; tmp[i]+=r[q[head]][y]-1; } for(int i=x;i<=n;i++) { if(tmp[i]>=x) return 1; } return 0; } void solve() { int tem=ans[k].res; for(int i=k;i>=2;i--) { ans[i].res=tem; int x=ans[i].x; int y=ans[i].y; a[x][y]=1; for(int j=1;j<=m;j++) { l[x][j]=a[x][j]*(l[x][j-1]+1); } for(int j=m;j>=1;j--) { r[x][j]=a[x][j]*(r[x][j+1]+1); } while(check(tem+1,y)) tem++; } ans[1].res=tem; for(int i=1;i<=k;i++) { printf("%d\n",ans[i].res); } } int main() { init(); dp(); solve(); return 0; }
(完)
CF480E Parking Lot(单调队列+dp然鹅并不是优化)
标签:mes 运算 memset pre clu 逻辑运算 bit font code
原文地址:https://www.cnblogs.com/ajmddzp/p/11621092.html