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;
    }
    
    
  • 相关阅读:
    28完全背包+扩展欧几里得(包子凑数)
    HDU 3527 SPY
    POJ 3615 Cow Hurdles
    POJ 3620 Avoid The Lakes
    POJ 3036 Honeycomb Walk
    HDU 2352 Verdis Quo
    HDU 2368 Alfredo's Pizza Restaurant
    HDU 2700 Parity
    HDU 3763 CDs
    POJ 3279 Fliptile
  • 原文地址:https://www.cnblogs.com/acceptedzhs/p/13968446.html
Copyright © 2011-2022 走看看