题目链接: 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;
}