题目:
http://codeforces.com/problemset/problem/520/D
题意:
有n 个点坐标(xi,yi)在坐标平面内,分别编号0~m.
在图上取点,每一次都要使图平衡.平衡的条件是:点(x,y) 在x 轴上,或者是(x,y-1) / (x-1,y-1) / (x+1, y-1) 上有点存在.
现在有两人a和b玩游戏, a先取数,每次取数都要保持图平衡.取到的数组成n进制的数.a要使得数越大,b使得数越小.
思路:
看了别人的代码了解的思路.
使用map存储所有的点坐标和编号.
先枚举所有的点,判断是否可以取,若可以则加入set -leap.
接着开始取数, i 为偶时,从leaf 尾取数, 奇时从头取数. 每次取完, 都要删除leaf中的标号, 且更新与它相关联的点, 看是否可以存在set中被取数.
AC.
#include <iostream>
#include <cstdio>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 9;
const int MAX = 100005;
map<pair<int, int>, int> ma;
set<pair<int, int> > s;
set<int> leaf;
int x[MAX], y[MAX], n;
void read()
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%d %d", &x[i], &y[i]);
pair<int, int> p = make_pair(x[i], y[i]);
ma[p] = i;
s.insert(p);
}
}
int cnt(int xx, int yy)
{
int res = 0;
for(int i = xx - 1; i <= xx + 1; ++i) {
if(s.find(make_pair(i, yy - 1)) != s.end()) res++;
}
return res;
}
bool isleaf(int xx, int yy)
{
for(int i = xx - 1; i <= xx + 1; ++i) {
if(s.find(make_pair(i, yy+1)) != s.end() &&
cnt(i, yy+1) == 1) return false;
}
return true;
}
void update(int xx, int yy)
{
for(int i = xx - 2; i <= xx + 2; ++i) {
for(int j = yy - 1; j <= yy + 1; ++j) {
pair<int, int> p = make_pair(i, j);
if(s.find(p) == s.end()) continue;
int id = ma[p];
if(leaf.find(id) != leaf.end()) leaf.erase(id);
if(isleaf(i, j)) leaf.insert(id);
}
}
}
void work()
{
for(int i = 0; i < n; ++i) {
if(isleaf(x[i], y[i])) leaf.insert(i);
}
ll ans = 0;
for(int i = 0; i < n; ++i) {
int num;
if(i % 2 == 0) num = *(--leaf.end());
else num = *(leaf.begin());
ans = (ans*n + num) % mod;
s.erase(make_pair(x[num], y[num]));
leaf.erase(num);
update(x[num], y[num]);
}
printf("%I64d\n", ans);
}
int main()
{
//freopen("in", "r", stdin);
read();
work();
return 0;
}