专栏文章

题解:AT_abc391_d [ABC391D] Gravity

AT_abc391_d题解参与者 7已保存评论 9

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
9 条
当前快照
1 份
快照标识符
@miqcxxis
此快照首次捕获于
2025/12/04 02:45
3 个月前
此快照最后确认于
2025/12/04 02:45
3 个月前
查看原文
像流星划过夜空,转瞬即逝的梦。
在平面直角坐标系中,有 NN 颗流星(shooting_star)划过,第 ii 颗的初始坐标(第 00 时刻坐标)为 (Xi,Yi)(X_i,Y_i)。保证 1XiW1 \leq X_i\leq W
每一个单位时刻,流星按如下规则运动:
  • 如果底部是满的既 (1,1),(2,1),,(W,1)(1,1),(2,1),\cdots,(W,1) 的位置上都有流星,那么这些流星在这个时刻末全部消失;否则底部的流星不动。
  • 其余不在底部的流星向下移动一个单位。
在看流星的 fyy 想问妳 QQ 个问题:询问第 AiA_i 个流星在 TiT_i 时刻是否存在。
妳非常聪明,很快注意到 QQ 很大,不可能一个一个处理,妳打算对于每一个流星,计算它消失的时刻。
如何计算每一个流星消失的时刻?妳很快发现流星消失是一轮一轮的。
考察横向和竖向的变化:
  • 横向:妳发现一轮消失的流星总是每一列中最低的一个。
  • 纵向:妳发现每一列中,低的流星总不会影响高的流星的运动状态。
以上是一些感性认识,我们现在转化为形式化语言。
  1. 考虑将流星按列放进优先队列。具体的,初始 (Xi,Yi)(X_i,Y_i) 放进 qXiq_{X_i}。其中 q1,q2,,qWq_1,q_2,\cdots,q_WWW 个小根堆(优先队列)。
  2. q1,q2,,qWq_1,q_2,\cdots,q_W 的队首。
    • 如果某个队列空了,那么以后的流星(包括这一轮)永不消失。
    • 否则取 q1,q2,,qWq_1,q_2,\cdots,q_W 的队首 yy 坐标的最大值为这一轮所有流星的消失时间 TmaxT_{max}注意临界问题,如果一个时刻 TTmaxT\ge T_{max} 那么这一轮的流星都在 TT 时刻消失过了,注意能取等号)。
    • 将所有队首出队。
  3. 不断执行操作 22,直至存在一个空队。
然后代码是很简单的,据笔者所知很多人这道题都死于细节。笔者自认为自己的代码细节很少好理解。
CPP
const int fyy=0;

int main()
{
    int N,W;
    cin>>N>>W;
    vector<priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>> q(W+1);
    vector<int> ans(N+1,(int)1e9+24);
    rep(i,1,N)
    {
        int X,Y;
        cin>>X>>Y;
        q[X].push({Y,i});
    }
    bool zxq=1; // 张修齐:是否可进行下一轮
    while(zxq)
    {
        int _max=fyy;
        rep(i,1,W)
        {
            if(q[i].empty())
            {
                zxq=fyy;
                break;
            }
            _max=max(_max,q[i].top().first);
        }
        if(!zxq) break;
        rep(i,1,W)
        {
            ans[q[i].top().second]=_max;
            q[i].pop();
        }
    }
    int Q;
    cin>>Q;
    while(Q--)
    {
        int T,A;
        cin>>T>>A;
        if(T>=ans[A])
            cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }
}

// 路虽远行则将至,事虽难做则必成。
流星姐姐珂愛喵~

评论

9 条评论,欢迎与作者交流。

正在加载评论...