stl模拟 Codeforces Round #295 (Div. 1) B. Cubes


题解:

Basically, the first player should maximize the lexicographical order of numbers, and the second player should minimize it. Thus, at every move the first player should choose the largest available number, and the second should choose the minimal one.

First of all, how do we check if the cube can be removed? It is impossible only if there is some cube "supported" by it (i.e., it has coordinates (x - 1, y + 1)(x, y + 1)(x + 1, y + 1)) such that our cube is the only one supporting it. This can be checked explicitly. The large coordinates' limitations do not allow us to store a simply array for that, so we should use an associative array, like a set in C++.

Now we should find the maximal/minimal number that can be removed. A simple linear search won't work fast enough, so we store another data structure containing all numbers available to remove; the structure should allow inserting, erasing and finding global minimum/maximum, so the set C++ structure fits again.

When we've made our move, some cubes may have become available or unavailable to remove. However, there is an O(1) amount of cubes we have to recheck and possibly insert/erase from our structure: the cubes (x ± 1, y) and (x ± 2, y) may have become unavailable because some higher cube has become dangerous (that is, there is a single cube supporting it), and some of the cubes(x - 1, y - 1)(x, y - 1) and (x + 1, y - 1) may have become available because our cube was the only dangerous cube that it has been supporting. Anyway, a simple recheck for these cubes will handle all the cases.

This solution is  if using the appropriate data structure.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
#include<queue>
#include<set>
#include<map>
#include<math.h>
#include<string>
using namespace std;
#define inf 0x3f3f3f3f
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:102400000,102400000")
#define ll long long
#define mp make_pair 
#define pb push_back
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
const double eps = 1e-9;
const ll mod = 1e9 + 9;

map<pair<int, int>, int> m;
struct node
{
	int x, y, id;
	bool operator<(const node &I) const{
		return id < I.id;
	}
}p[200020];
set<node> s;

int f[200010];   //标记已经使用的,就是set中已经删除的

int vis[200020]; //标记当前可以移动的,在set里里面的

bool ok(node s, node t)//存在非t块 的其他块支撑
{
	for (int i = -1; i <= 1; i++)
	{
		node r;
		r.y = s.y - 1;
		r.x = s.x + i;
		if (m[mp(r.x, r.y)] != 0 && r.x != t.x && f[m[mp(r.x, r.y)]-1] == 0)
			return true;
	}
	return false;
}
bool is_ok_rm(node t)
{
	for (int i = -1; i <= 1; i++)
	{
		node r;
		r.y = t.y + 1;
		r.x = t.x + i;
		if (m[mp(r.x, r.y)] == 0) continue;
		if (f[m[mp(r.x, r.y)]-1] == 1) continue;
		if (!ok(r, t))
			return false;
	}
	return true;
}
void del(node t)
{
	for (int i = -1; i <= 1; i++)
	{
		node r;
		r.y = t.y - 1;
		r.x = t.x + i;
		if (m[mp(r.x, r.y)] == 0) continue;
		if (f[m[mp(r.x, r.y)] - 1] == 1) continue;
		if (is_ok_rm(r))
		{
			r.id = m[mp(r.x, r.y)]-1;
			s.insert(r);
			vis[r.id] = 1;
		}
	}
	for (int i = -2; i <= 2; i++)
	{
		if (i == 0) continue;
		node r;
		r.y = t.y;
		r.x = t.x + i;
		int h = m[mp(r.x, r.y)];
		if (h != 0 && vis[h - 1] == 1 && !is_ok_rm(r))
		{
			r.id = h - 1;
			vis[h - 1] = 0;
			s.erase(r);
		}
	}
}
int main()
{
	int n;
	cin >> n;
	memset(f, 0, sizeof(f));
	mem(vis,0);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d%d", &p[i].x, &p[i].y);
		p[i].id = i - 1;
		m[mp(p[i].x,p[i].y)] = i;
	}
	for (int i = 1; i <= n; i++)
	{
		if (is_ok_rm(p[i]))
		{
			s.insert(p[i]);
			vis[p[i].id] = 1;
		}
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++)
	{
		node t;
		if (i % 2 == 1)
			t = *(s.rbegin());
		else
			t = *(s.begin());
		ans = ans*n%mod + t.id;
		s.erase(t);
		f[t.id] = 1;
		del(t);
	}
	cout << ans << endl;
	//system("pause");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值