题解:洛谷 P10801([CEOI 2024] 海战)
1. Description
捷克海军司令官翁德拉刚刚晋升为大元帅,正享受着新职位的安稳,却突然被政府通知海军将被裁撤。
翁德拉决心证明捷克海军的重要性。他通过间谍得知,一场四国海军巨舰对决即将展开。如果能赢得这场战役,无疑能向政府有力地展示海军价值。
然而,捷克海军既无战舰也无港口。但翁德拉想到,如果他的间谍能夺取几艘参战舰艇,或许还有一线生机。关键是,如何预知哪些船能在这场海战中幸存下来呢?
海战规则如下:
- 战前,第 \(i\) 艘战舰位于坐标 \((x_i, y_i)\) 处,其中 \(x_i\) 和 \(y_i\) 均为偶数。每艘战舰隶属于北方、南方、东方或西方舰队之一。
- 海战分回合进行。每回合:
- 每艘战舰同时向其所属舰队方向移动一格。
- 如果两艘或以上战舰占据同一格,它们将相撞沉没,从海图上消失。
- 当不再发生碰撞时,海战结束。存活的战舰是指海战结束后仍留在海图上的战舰。
各舰队战舰的移动方向及坐标变化如下: - 北方舰队:\(y\) 坐标减 \(1\)
- 南方舰队:\(y\) 坐标加 \(1\)
- 东方舰队:\(x\) 坐标加 \(1\)
- 西方舰队:\(x\) 坐标减 \(1\)
2. Solution
首先,暴力做法不难想到,暴力枚举所有战舰对,计算出它们相撞的时间,然后扔进一个小根堆中依次处理即可,时间复杂度 \(O(n^2)\)。
我们考虑优化这个做法,去除掉一定不会用到的战舰对。
考虑一艘向南的战舰 \(i\),一艘向东的战舰 \(j\),如果它们会在时间 \(t\) 相撞,那么满足 \(x_i+t=x_j,y_i+t=y_j\),简单整理就有 \(x_i-y_i=x_j-y_j\)。
就是说,这两艘战舰想要相撞,必然就有横纵坐标之差相等,所以我们按照横纵坐标差将战舰分类。但是这样并没有实际作用,我们仍然需要进一步考虑。
如果可以相撞,一定有 \(t=x_i-x_j\),我们发现,如果将这一类的战舰按照 \(x\) 排序,一定有相邻的战舰对优于不相邻的战舰对,那么就可以将有用的战舰对优化到 \(O(n)\) 了。
其余 \(5\) 种组合,读者可自行推导,这里给出结论:
向北和向东:\(x-y\) 相等,按照 \(x\) 坐标排序。
向北和向西:\(x+y\) 相等,按照 \(x\) 坐标排序。
向北和向南:\(x\) 相等,按照 \(y\) 坐标排序。
向东和向西:\(y\) 相等,按照 \(x\) 坐标排序。
向东和向南:\(x+y\) 相等,按照 \(x\) 坐标排序。
向西和向南:\(x-y\) 相等,按照 \(x\) 坐标排序。
可以使用 set 维护同一类的战舰。
在小根堆处理的时候,我们每一次取出堆顶的战舰对,判断是否相撞,然后在对应的 set 中删除这两艘战舰,最后加入新的可能的战舰对即可,不难判断这样的时间复杂度是 \(O(n\log n)\) 的。
3. Code
/*by ChenMuJiu*/
/*略去缺省源与快读快写*/
const int N=2e5+5,dx[]={0,1,-1,0},dy[]={-1,0,0,1},inf=0x3f3f3f3f;
int n;
int x[N],y[N],d[N],t[N];
struct Node{
int first,second,idx;
bool operator <(const Node &T)const{
if(first^T.first)return first<T.first;
return second<T.second;
}
};
set<Node>idx[4][4];
struct event{
int t,x,y;
bool operator >(const event &T)const{
return t>T.t;
}
};
priority_queue<event,vector<event>,greater<event>>q;
int cal(int i,int j){
if(d[i]==d[j])return -1;
int t=-1;
if(dx[d[i]]!=dx[d[j]])t=(x[i]-x[j])/(dx[d[j]]-dx[d[i]]);
if(dy[d[i]]!=dy[d[j]])t=(y[i]-y[j])/(dy[d[j]]-dy[d[i]]);
if(t<0)return -1;
if(x[i]+t*dx[d[i]]!=x[j]+t*dx[d[j]])return -1;
if(y[i]+t*dy[d[i]]!=y[j]+t*dy[d[j]])return -1;
return t;
}
void delet(int id){
set<Node>::iterator it;
if(d[id]==0){
it=idx[0][1].lower_bound({x[id]-y[id],x[id],id});
if(it!=idx[0][1].begin()&&next(it)!=idx[0][1].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][1].erase(it);
it=idx[0][2].lower_bound({x[id]+y[id],x[id],id});
if(it!=idx[0][2].begin()&&next(it)!=idx[0][2].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][2].erase(it);
it=idx[0][3].lower_bound({x[id],y[id],id});
if(it!=idx[0][3].begin()&&next(it)!=idx[0][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][3].erase(it);
}else if(d[id]==1){
it=idx[0][1].lower_bound({x[id]-y[id],x[id],id});
if(it!=idx[0][1].begin()&&next(it)!=idx[0][1].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][1].erase(it);
it=idx[1][2].lower_bound({y[id],x[id],id});
if(it!=idx[1][2].begin()&&next(it)!=idx[1][2].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[1][2].erase(it);
it=idx[1][3].lower_bound({x[id]+y[id],x[id],id});
if(it!=idx[1][3].begin()&&next(it)!=idx[1][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[1][3].erase(it);
}else if(d[id]==2){
it=idx[0][2].lower_bound({x[id]+y[id],x[id],id});
if(it!=idx[0][2].begin()&&next(it)!=idx[0][2].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][2].erase(it);
it=idx[1][2].lower_bound({y[id],x[id],id});
if(it!=idx[1][2].begin()&&next(it)!=idx[1][2].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[1][2].erase(it);
it=idx[2][3].lower_bound({x[id]-y[id],x[id],id});
if(it!=idx[2][3].begin()&&next(it)!=idx[2][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[2][3].erase(it);
}else{
it=idx[0][3].lower_bound({x[id],y[id],id});
if(it!=idx[0][3].begin()&&next(it)!=idx[0][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[0][3].erase(it);
it=idx[1][3].lower_bound({x[id]+y[id],x[id],id});
if(it!=idx[1][3].begin()&&next(it)!=idx[1][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[1][3].erase(it);
it=idx[2][3].lower_bound({x[id]-y[id],x[id],id});
if(it!=idx[2][3].begin()&&next(it)!=idx[2][3].end()){
int t=cal(prev(it)->idx,next(it)->idx);
if(~t)
q.push({t,prev(it)->idx,next(it)->idx});
}
idx[2][3].erase(it);
}
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
read(x[i]),read(y[i]);
char c=getchar();
while(c!='N'&&c!='E'&&c!='W'&&c!='S')c=getchar();
if(c=='N')d[i]=0;
else if(c=='E')d[i]=1;
else if(c=='W')d[i]=2;
else d[i]=3;
if(d[i]==0){
idx[0][1].insert({x[i]-y[i],x[i],i});
idx[0][2].insert({x[i]+y[i],x[i],i});
idx[0][3].insert({x[i],y[i],i});
}else if(d[i]==1){
idx[0][1].insert({x[i]-y[i],x[i],i});
idx[1][2].insert({y[i],x[i],i});
idx[1][3].insert({x[i]+y[i],x[i],i});
}else if(d[i]==2){
idx[0][2].insert({x[i]+y[i],x[i],i});
idx[1][2].insert({y[i],x[i],i});
idx[2][3].insert({x[i]-y[i],x[i],i});
}else{
idx[0][3].insert({x[i],y[i],i});
idx[1][3].insert({x[i]+y[i],x[i],i});
idx[2][3].insert({x[i]-y[i],x[i],i});
}
}
for(int i=0;i<4;i++){
for(int j=i+1;j<4;j++){
auto it=idx[i][j].begin();
while(it!=idx[i][j].end()){
if(next(it)!=idx[i][j].end()){
int t=cal(next(it)->idx,it->idx);
if(~t)q.push({t,next(it)->idx,it->idx});
}
it++;
}
}
}
memset(t,0x3f,sizeof(t));
while(!q.empty()){
auto tmp=q.top();
q.pop();
if(t[tmp.x]!=inf&&t[tmp.x]!=tmp.t)continue;
if(t[tmp.y]!=inf&&t[tmp.y]!=tmp.t)continue;
if(t[tmp.x]==inf){
t[tmp.x]=tmp.t;
delet(tmp.x);
}
if(t[tmp.y]==inf){
t[tmp.y]=tmp.t;
delet(tmp.y);
}
}
for(int i=1;i<=n;i++)
if(t[i]==inf)write(i),Nxt;
}

浙公网安备 33010602011771号