zoukankan      html  css  js  c++  java
  • 【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;
    }
    
    
  • 相关阅读:
    http缓存机制与原理
    BFC与浮动
    05ICMP协议与ARP协议(IP协议中重要协议)
    04IP编址(网络层)
    03以太网帧结构(链路层 IEEE802.3)
    02传输介质简介
    shell 脚本 2
    shell 脚本 1
    shell 中时间 表达
    sed 行编辑器
  • 原文地址:https://www.cnblogs.com/acceptedzhs/p/13968446.html
Copyright © 2011-2022 走看看