一群青蛙正在摧毁Byteotia所有的庄稼。一个叫Byteasar的农夫决定使用一种放在田里的奇特的“scarefrogs”来吓跑他们,所有的青蛙在跳跃过程中都尽量使自己离他们越远越好,即是让自己离最近的scarefrog越远越好。Byteasar的田是块矩形的土地。青蛙们跳跃的方向平行于坐标轴并且每次跳跃的距离为1,一条跳跃路线的scarefrogs-距离为路径上所有点距离所有scarefrogs的最近距离。Byteasar已经知道青蛙们的出发位置和目的地位置,所以他在田里放置了若干个scarefrogs。
他请求你帮忙写一个程序找一条路径使得该路径的scarefrogs-距离最大。
第一行包含两个整数: wx 和 wy 分别表示田地的宽和长 (2≤wx,wy≤1000) 。
第二行包含四个整数: px,py,kx,ky ,其中 (px,py) 为青蛙的起始位置, (kx,ky) 为目的地位置 (1≤px,kx≤wx,1≤py,ky≤wy) 。
第三行一个整数 n 表示scarefrogs的总数 (1≤n≤wx⋅wy) 。接下来 n 行描述所有scarefrogs的坐标。坐标用 xi 和 yi 描述第 i 个 scarefrog的位置 (1≤xi≤wx,1≤yi≤wy) 。没有两个scarefrogs在同一个位置出现并且不会出现在 (px,py) 或 (kx,ky) 上。
一个整数代表目标路径scarefrog距离的平方。如果青蛙不可避免遇到某些scarefrog那么答案为0。
5 5 1 1 5 5 2 3 3 4 2
4
我就是看题面格式不爽来打我呀~
然而这道题是关于Frog的(雾
一眼二分scarefrog-距离判断是否可行,想了一下两两连线判断起点终点是否在同一区域内,然而并不会写,而且这道题路径只能沿着网格走。所以只要删掉不能走的点BFS即可。
BFS不是问题,问题是处理出每个点到最近的scarefrog的距离。
采用单调队列的思想。对于每一个 x 坐标按照 y 坐标递增的顺序处理。
显而易见的是, y 坐标相同的scarefrog只取 x 坐标到当前 x 坐标最近的即可。则至多有1000只scarefrog对答案产生影响。
按照 y 坐标从小到大处理scarefrog。考虑当前的节点为 (x,y) ,两只scarefrog坐标为 (xa,ya) , (xb,yb) ,则b到当前点距离小于a,当且仅当
代码
#include
#include
#include
#include
#include
#include
using namespace std;
struct pos{
int x, y;
pos(){}
pos(int X, int Y):x(X), y(Y){}
bool operator<(const pos &a)const{
return y==a.y?xx:yy;
}
}st, en, frog[1000010], use[1010]; // use数组表示每行要用的scarefrog
// dis:最近scarefrog的距离 pts:这行scarefrog的指针 rg:这行scarefrog的范围 bel:选中scarefrog的编号
int n, m, t, dis[1010][1010], pts[1010], rg[1010], bel[1010];
double stk[1010]; bool v[1010][1010];
queue<pos> Q;
inline int rd(){
int a=0; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) (a*=10)+=c-'0', c=getchar();
return a;
}
// 计算大柿子
double calc(int xa, int ya, int xb, int yb, int x){
return 1.*(xa*xa-xb*xb+2*x*(xb-xa))/(ya-yb)+ya+yb;
}
int dist(int dx, int dy){
return dx*dx+dy*dy;
}
void pre(){
sort(frog, frog+t);
// 处理出每一x坐标的scarefrog范围
for(int i=0;iint p=frog[i].y; pts[p]=i;
while(iy==p) i++;
rg[p]=i;
}
// 处理dis
for(int i=1;i<=n;i++){
int h=0; use[h].x=1000, use[h++].y=-1000;
for(int j=1;j<=m;j++){
if(!rg[j]) continue;
// 更新距离当前x坐标最近的scarefrog
if(pts[j]+1abs(i-frog[pts[j]].x)>abs(i-frog[pts[j]+1].x))
pts[j]++;
use[h++]=frog[pts[j]];
}
int h2=0;
for(int j=1;juse[j].x, use[j].y, use[bel[h2-1]].x, use[bel[h2-1]].y, i);
// 维护单调栈
while(h2&&tt<=stk[h2-1]) h2--, tt=calc(use[j].x, use[j].y, use[bel[h2-1]].x, use[bel[h2-1]].y, i);
bel[h2]=j; stk[h2++]=tt;
}
int pt=0;
for(int j=1;j<=m;j++){
// 找到最近点
while(pt+11]*2) pt++;
dis[i][j]=dist(i-use[bel[pt]].x, j-use[bel[pt]].y);
}
}
}
bool bfs(int ex){
memset(v, 0, sizeof v);
Q.push(st); v[st.x][st.y]=1;
pos w;
while(!Q.empty()){
w=Q.front(); Q.pop();
if(w.x>1) if(dis[w.x-1][w.y]>=ex) if(!v[w.x-1][w.y]){v[w.x-1][w.y]=1; Q.push(pos(w.x-1, w.y));}
if(w.xif(dis[w.x+1][w.y]>=ex) if(!v[w.x+1][w.y]){v[w.x+1][w.y]=1; Q.push(pos(w.x+1, w.y));}
if(w.y>1) if(dis[w.x][w.y-1]>=ex) if(!v[w.x][w.y-1]){v[w.x][w.y-1]=1; Q.push(pos(w.x, w.y-1));}
if(w.y<m) if(dis[w.x][w.y+1]>=ex) if(!v[w.x][w.y+1]){v[w.x][w.y+1]=1; Q.push(pos(w.x, w.y+1));}
}
return v[en.x][en.y];
}
int bin(){
int l=0, r=min(dis[st.x][st.y], dis[en.x][en.y])+1, m;
while(r-l!=1){
m=(l+r)>>1;
if(bfs(m)) l=m;
else r=m;
}
return l;
}
int main(){
n=rd(), m=rd();
st.x=rd(), st.y=rd(); en.x=rd(), en.y=rd();
t=rd();
for(int i=0;ix=rd(), frog[i].y=rd();
pre();
// for(int i=1;i<=n;i++)
// for(int j=1;j<=m;j++)
// printf("%d%c", dis[i][j], j==m?'\n':' ');
printf("%d\n", bin());
return 0;
}
一开始是不知道单调栈还可以维护两两比较这种东西的……学到了。