两个人的策略是显然的:因为先选的是高位,所以先手选最大数,后手选最小数
所以可以用一个set来维护当前可以拿的cube
这题刚开始想了一个拓扑排序,但这显然不对
例如 * 下一行左边的和右边的是可以拿走的
***
一个重要的结论是,一个方块可以拿,当且仅当所有以他为根基的方块都有不止一个根基
所以以这个方法先选出所有的可拿方块
然后每删除一个方块,就在以他为中心的5*5范围内(这是可波及影响的最大范围)判断可拿性是否有变动(注意已经拿过的记为false,不参与计算)
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <utility> #include <map> #include <stack> #include <set> #include <vector> #include <queue> #include <deque> #define x first #define y second #define mp make_pair #define pb push_back #define LL long long #define Pair pair<int,int> #define LOWBIT(x) x & (-x) using namespace std; const LL MOD=1e9+9; int n; bool visited[100048]; Pair a[100048]; map<Pair,int> m; set<int> s; inline int cnt(int x,int y) { int res=0; for (int i=-1;i<=1;i++) if (m[mp(x+i,y-1)] && !visited[m[mp(x+i,y-1)]]) res++; return res; } inline bool isleaf(int num) { int xx=a[num].x,yy=a[num].y,i; for (i=-1;i<=1;i++) if (m[mp(xx+i,yy+1)] && !visited[m[mp(xx+i,yy+1)]] && cnt(xx+i,yy+1)==1) return false; return true; } void update(int num) { int i,j,xx=a[num].x,yy=a[num].y,id; for (i=xx-2;i<=xx+2;i++) for (j=yy-2;j<=yy+2;j++) { //if (visited[i][j]) continue; id=m[mp(i,j)]; if (m[mp(i,j)]==0) continue; if (visited[id]) continue; if (s.find(id)!=s.end()) s.erase(id); if (isleaf(id)) s.insert(id); } } int main () { int i; scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d%d",&a[i].x,&a[i].y); m[a[i]]=i; } for (i=1;i<=n;i++) if (isleaf(i)) s.insert(i); int t=0; LL num; LL ans=0; for (i=1;i<=n;t^=1,++i) { //cout<<i<<endl; if (t==0) { //cout<<s.size()<<endl; num=(LL)*(--s.end());//cout<<"*"; ans=((ans*n)%MOD+num-1)%MOD; s.erase(--s.end()); visited[num]=true; update(num); } else { num=(LL)*s.begin(); ans=((ans*n)%MOD+num-1)%MOD; s.erase(s.begin()); visited[num]=true; update(num); } } cout<<ans<<endl; return 0; }