Codeforces Round #295 (Div. 2) D

题目链接: http://codeforces.com/contest/520/problem/D

题目大意: 

     在一个XOY面上有很多cube,每个cube给定一个位置坐标,它(x,y)能稳定存在的条件是:要么坐标形如(x,y=0),要么在(x-1,y-1),(x,y-1),(x+1,y-1)方向上存在一个cube.现在给定一个初始的堆积方式,输入保证整体是稳定的,输入从上到下的cube分数从0到m-1.现在两个人A,B轮流从这堆cube中拿走一个cube,直到拿完为止,这样会形成一个分数(m-进制),最后算出m进制数在十进制下模1e9的结果.A,B每次拿走一个cube后必须保持其余的cube稳定,A希望最后的结果尽量大,B希望最后结果尽量小,两个人都是会玩的,问在A先手的情况下的结果.

分析:

    因为每个cube的分数都不相同,所以在A的回合只用考虑所有可以被拿走的cube中分值最大的,而在B的回合只用考虑那个最小的.关键是维护一个可以被拿走的cube集合,并能快速的选出最大的和最小的.用set维护即可.最大的为(*st.rbegin()),最小的为(*st.begin()),因为cube坐标x,y可能很大,所以用一个map<pair<int,int>,int>来得到指定x,y位置的得分.然后考虑如果A拿走一个之后可能影响到的cube.(1)左右两侧四个cube,因为如果他们之前是可以被拿走的,那么拿走一个之后可能就变得不可以被拿走了.(2)下面的三个,因为如果他们之前是不可以被拿走的,拿走他们上面那个之后,他们就有可能可以被拿走了.

做法就是在每次拿走一个之后,检测上面说的可能被影响到的那些cube,维护set即可.

AC代码如下:

#include <iostream>
#include <cstdio>
#include <set>
#include <map>
#include <vector>
#include <cstring>
using namespace std;
#define mp(x,y) make_pair(x,y)
const int MOD  = 1000000009;
const int dir1[3][2]={{-1,1},{0,1},{1,1}};
const int dir2[3][2]={{-1,-1},{0,-1},{1,-1}};
const int dir3[4][2]={{-1,0},{1,0},{-2,0},{2,0}};
set<int> st;
map<pair<int,int>,int> Mp;
vector<int> res;
vector<int> X,Y;
bool check(int x,int y)
{
    if(!Mp.count(mp(x,y))) return 0;
    for(int i=0;i<3;i++)
    {
        int newx,newy;
        bool sign=0;
        newx=x+dir1[i][0];newy=y+dir1[i][1];
        if(!Mp.count(mp(newx,newy))) continue;
        for(int j=0;j<3;j++)
        {
            int nowx,nowy;
            nowx=newx+dir2[j][0];nowy=newy+dir2[j][1];
            if(nowx==x&&nowy==y) continue;
            if(Mp.count(mp(nowx,nowy))) {sign=1;break;}
        }
        if(!sign) return 0;
    }
    return 1;  //可以删
}
int main()
{
    //freopen("in.txt","r",stdin);
    int m;
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
      int x,y;
      scanf("%d%d",&x,&y);
      Mp[mp(x,y)]=i;
      X.push_back(x);
      Y.push_back(y);
    }
    for(int i=0;i<m;i++)
    {
      if(check(X[i],Y[i])) st.insert(i);
    }
    bool sign=1;
    while(!st.empty())
    {
        int now;
        if(!sign)
          now=(*st.begin());
        else
          now=(*st.rbegin());
        int x,y;
        x=X[now];y=Y[now];
        res.push_back(now);
        Mp.erase(mp(x,y));
        st.erase(now);
        int newx,newy;
        //看是否左右两侧的四个从可删变为不可删
        for(int i=0;i<4;i++)
        {
            newx=x+dir3[i][0];newy=y+dir3[i][1];
            if(Mp.count(mp(newx,newy))&&st.count(Mp[mp(newx,newy)])&&!check(newx,newy))
               st.erase(Mp[mp(newx,newy)]);
        }
        //看下面三个是否从不可删变成了可删
        for(int i=0;i<3;i++)
        {
            newx=x+dir2[i][0];newy=y+dir2[i][1];
            if(check(newx,newy)&&!st.count(Mp[mp(newx,newy)])) st.insert(Mp[mp(newx,newy)]);
        }
        sign=1-sign;
    }
    __int64 Res=0,temp=1;
    for(int i=m-1;i>=0;i--)
    {
        //cout<<Res<<endl;
        Res=(Res+(res[i]*temp)%MOD)%MOD;
        temp=(temp*m)%MOD;
    }
    printf("%I64d\n",Res);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值