【51Nod】1530 稳定方块 题解

原题链接:点这里

很明显,瓦西亚会取当前能够拆的方块中编号最大的一个,皮台亚会取当前能够拆的方块中编号最小的一个

证明很简单,以瓦西亚为例,若瓦西亚不取最大的一个,就算后面全取最大的也抵不过当前与最优解的差距。

那么,我们可以维护一个\(set\),存放当前所有能够拆的方块的编号。

初始,我们把所有能拆的方块加入集合。每次,我们取集合中编号最大/最小的方块,累加答案,然后寻找它左下/下方/右下方的方块,看这三个方块能否被拆掉。若能,则加入至集合中。这样依次处理,直到集合为空即可。

两个要点:

  1. 如何判断当前方块能否被拆?枚举它左上/上方/右上方的方块,看去掉当前方块后,这三个方块还是否平衡即可。
  2. 由于一些原因,集合中编号最大/最小的方块不一定是合法的。我们要不停地取编号最大/最小的方块,直到当前方块合法才行。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MOD=1e9+9,N=100010;
struct Node{
    int x,y,id;
    bool operator<(const Node& a)const{return id<a.id;}
};
unordered_map<ll,int> vis;
set<Node> s;
int m,sx[N],sy[N];
ll ans;
inline ll mp(int x,int y){//当前点坐标的编号
    return (ll)x*998244853+y;
}

inline bool judge(int x,int y){//判断当前方块能否被拆
    for(int i=-1;i<=1;i++){
        int xx=x+i,yy=y+1,cnt=0;
        if(!yy||vis.find(mp(xx,yy))==vis.end()) continue;
        for(int j=-1;j<=1;j++){
            if(vis.find(mp(xx+j,yy-1))!=vis.end()) cnt++;
        }
        if(cnt<2) return false;
    }
    return true;
}

int main(){
    scanf("%d",&m);
    for(int i=0;i<m;i++) scanf("%d%d",&sx[i],&sy[i]),vis[mp(sx[i],sy[i])]=i;
    for(int i=0;i<m;i++){
        if(judge(sx[i],sy[i])) s.insert((Node){sx[i],sy[i],i});
    }
    while(!s.empty()){
        set<Node>::iterator it;Node x;
        while(!s.empty()){
            it=s.end();it--;
            x=*it;s.erase(it);
            if(judge(x.x,x.y)) break;
        }
        ans=((ans*m)%MOD+x.id)%MOD;
        cout<<x.id<<endl;
        vis.erase(mp(x.x,x.y));
        for(int i=-1;i<=1;i++){
            int xx=x.x+i,yy=x.y-1;
            if(yy<0||vis.find(mp(xx,yy))==vis.end()) continue;
            if(judge(xx,yy)) s.insert((Node){xx,yy,vis[mp(xx,yy)]});
        }
        if(s.empty()) break;
        while(!s.empty()){
            it=s.begin();
            x=*it;s.erase(it);
            if(judge(x.x,x.y)) break;
        }
        ans=((ans*m)%MOD+x.id)%MOD;
        cout<<x.id<<endl;
        vis.erase(mp(x.x,x.y));
        for(int i=-1;i<=1;i++){
            int xx=x.x+i,yy=x.y-1;
            if(yy<0||vis.find(mp(xx,yy))==vis.end()) continue;
            if(judge(xx,yy)) s.insert((Node){xx,yy,vis[mp(xx,yy)]});
        }
    }
    cout<<ans<<endl;
    return 0;
}

上一篇:51Nod 1486 大大走格子


下一篇:51Nod 1350 斐波那契表示