[USACO20DEC] Stuck in a Rut S
良心模拟题!!!
题目大意
无限大的网格图上有 \(N\) 头奶牛,第 \(i\) 头奶牛的坐标为 \((x_i,y_i)\),一些奶牛朝向北面,一些奶牛朝向东面。
每一小时,若奶牛遇到了一个没有被吃过草的格子,她会吃掉当前这一格的全部草,并向前走一步;否则它会在这一格停住,不再往前走。特别地,若两头奶牛同时到达某一格子,它们会分享这个格子的草,并继续向前走。
我们称奶牛 \(a\) 阻碍了奶牛 \(b\) 当且仅当 \(b\) 到达了一个 \(a\) 已经吃过草的格子而停下,而「阻碍」关系具有传递性,即若 \(a\) 阻碍了 \(b\),且 \(b\) 阻碍了 \(c\),那么我们认为 \(a\) 也阻碍了 \(c\)。
现在要求求出每头奶牛阻碍的奶牛数量。
题目分析
牛 \(a\) 会遇到牛 \(b\) 走过的方格,有两种情况:
-
\(way[a]=N,way[b]=E,x[a]>x[b],y[a]<y[b]\)。
-
\(way[a]=E,way[b]=N,x[a]<x[b],y[a]>y[b]\)。
于是我们将所有满足条件的 \(a,b\) 放到结构体 \(tmp\) 中。
在 \(tmp\) 中,我们存储了所有奶牛的交点:
\(id1,id2\) 分别存满足条件的 \(\verb!East!\) 奶牛和 \(\verb!North!\) 奶牛的下标;
\(x,y\) 则表示交点坐标。
随后将这些交点从左往右排序。
最后,再遍历依次数组得到答案。
具体地:
(下面记向东方走的奶牛为东方奶牛,向北方走的奶牛为北方奶牛)
若 \(|tmp[i].x-x[east]|>|tmp[i].y-y[north]|\),代表交点距离北方奶牛的距离更近一些,于是将 \(ans[north]\) 加上 \(ans[east]+1\)。
另一种离东方奶牛的距离更近的情况同理。
时间复杂度 \(\mathcal{O}(n^2)\)。
代码
const int ma=1005;
struct Node
{
char opt;
int x,y;
int ans;
};
Node node[ma];
struct Answer
{
int id1,id2;//id1 存 East,id2 存 North
int x,y;
};
Answer tmp[ma*ma];
bool vis[ma];
int n;
int idx;
inline bool cmp(Answer x,Answer y)
{
if(x.x!=y.x)
{
return x.x<y.x;
}
return x.y<y.y;
}
inline int Abs(int x)
{
return x>0?x:-x;
}
int main(void)
{
speed_up();
n=read();
for(register int i=1;i<=n;i++)
{
cin>>node[i].opt;
node[i].x=read(),node[i].y=read();
}
for(register int i=1;i<=n;i++)
{
for(register int j=i+1;j<=n;j++)
{
if(node[i].opt=='E' && node[j].opt=='N' && node[i].x<node[j].x && node[i].y>node[j].y)
{
tmp[++idx].x=node[j].x,tmp[idx].y=node[i].y;
tmp[idx].id1=i,tmp[idx].id2=j;
}
else if(node[i].opt=='N' && node[j].opt=='E' && node[i].x>node[j].x && node[i].y<node[j].y)
{
tmp[++idx].x=node[i].x,tmp[idx].y=node[j].y;
tmp[idx].id1=j,tmp[idx].id2=i;
}
}
}
sort(tmp+1,tmp+idx+1,cmp);
// for(register int i=1;i<=idx;i++)
// {
// printf("%d %d %d %d\n",tmp[i].id1,tmp[i].id2,tmp[i].x,tmp[i].y);
// }
for(register int i=1;i<=idx;i++)
{
int east=tmp[i].id1,north=tmp[i].id2;
if(vis[east]==false && vis[north]==false)
{
if(Abs(tmp[i].x-node[east].x)>Abs(tmp[i].y-node[north].y))
{
vis[east]=true;
node[north].ans+=node[east].ans+1;
}
else if(Abs(tmp[i].x-node[east].x)<Abs(tmp[i].y-node[north].y))
{
vis[north]=true;
node[east].ans+=node[north].ans+1;
}
}
}
for(register int i=1;i<=n;i++)
{
printf("%d\n",node[i].ans);
}
return 0;
}