題目大意:給你一個n*m的格子,有些格子有障礙,要你找到一個最小的正方形格子,使得這個正方形沒有覆蓋障礙且去掉這個正方形後(1,1)與(n,m)就不連通了
n<=1500 m<=1500
這題首先要找到從起點到終點的左手路徑與右手路徑,左手路徑就是用左手一直扶着牆壁走,右手路徑就是用右手一直扶着牆壁走。如果一個正方形可以覆蓋左右手路徑就能讓他不連通
首先暴搜每個點,把它作爲正方形的右上角點,再找到一個最小的邊長,mw,使得這個正方形可以阻斷(如果任意的合法的mw都不能使得其阻斷,就是最大的合法的邊長),
如果這個正方形可以阻斷,且這個正方形中沒有障礙就可以用mw來更新答案了。
我開始的做法是二分找mw,結果發現慢的飛起,是O(n^2logn)的,後來經過仔細研究終於找到了一種去除log的方法
對於一個點(i,j)它的mw是k,那麼(i,j+1)的mw<=k+1,這個是很顯然的,因爲以(i,j+1)爲右上角,邊長爲k+1的正方形是包含以(i,j)爲右上角,邊長爲k的正方形的
所以我們每次求一個點的mw時,就把上一個點的mw+1,在while mw-1也可以阻斷路徑時就把mw-1,這樣就可以求出mw了,因爲mw只加了n^2次,所以複雜度是O(n^2)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1511;
const int ax[]={-1,0,1,0},ay[]={0,1,0,-1};
int n,m; char map[maxn][maxn];
void init(){
scanf("%d%d",&m,&n);
for (int i=1;i<=n;++i) scanf("%s",map[i]+1);
}
bool vis[maxn][maxn];
inline bool cvis(int x,int y){return x<=n && x>=1 && y<=m && y>=1 && map[x][y]=='.';}
void get(int k,int x,int y,int w){
while (x!=n || y!=m){
vis[x][y]=1; int dx,dy,dw;
dw=(w+k+4)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
dw=w,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
dw=(w-k+4)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
dw=(w+2)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
}
}
struct Tmx{
int a[maxn][maxn];
void getpxsm(){
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j)
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
inline int Query(int x1,int y1,int x2,int y2){
return a[x2][y2]-a[x1][y2]-a[x2][y1]+a[x1][y1];
}
}mp,lt,rt;
inline bool check(int x,int y,int dx,int dy){
return (x || y) && (dx!=n || dy!=m) &&
lt.Query(x,y,dx,dy) && rt.Query(x,y,dx,dy);
}
void work(){
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) mp.a[i][j]=map[i][j]=='#';
mp.getpxsm(); get(-1,1,1,1);
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) lt.a[i][j]=vis[i][j]; lt.getpxsm();
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) vis[i][j]=0; get(1,1,1,2);
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) rt.a[i][j]=vis[i][j]; rt.getpxsm();
int ans=min(n,m)+1,ax=-1,ay;
for (int i=1;i<=n;++i){
int mw=0;
for (int j=1;j<=m;++j){
++mw;
while (mw && (i+mw-1>n || mp.Query(i-1,j-mw,i+mw-1,j))) --mw;
while (mw>1 && check(i-1,j-mw+1,i+mw-2,j)) --mw;
if (mw<ans && check(i-1,j-mw,i+mw-1,j)) ans=mw,ax=i,ay=j-mw+1;
}
}
if (ax==-1) puts("Impossible"); else printf("%d %d %d\n",ans,ay,ax);
}
int main(){
init();
work();
return 0;
}