【Codeforces】Codeforces Round #295 (Div. 2) D. Cubes | STL、模拟

57 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【Codeforces】Codeforces Round #295 (Div. 2) D. Cubes | STL、模拟

题目链接

Problem - 520D - Codeforces

题目

image.png

题目大意

二维平面内有一个坐标系 xOy,有一堆正方形。每个正方形的边长为 1,第 ii 个正方形的左下角的坐标为 (xi,yi)(x_i,y_i)。如果我们称若干个正方形组成的系统是稳定的,则任意一个坐标 (xi,yi)(x_i,y_i) 若其为一个正方形的左下角,须满足下述两个条件之一:

  • yi=0y_i=0
  • (xi1,yi1)(x_i-1,y_i-1)(xi,yi1)(x_i,y_i-1)(xi+1,yi1)(x_i+1,y_i-1) 中至少一个是某正方形的左下角。

最初给定一个稳定的正方形系统,共包含 mm 个正方形,编号为 0,1,2,...,m10,1,2,...,m-1。每次操作看可以选择一个正方形并移除,每次操作后正方形系统应依然稳定。则 mm 次操作后,被移除的正方形按照被移除的顺序依次排列,其编号会形成一个 mmmm 进制数。

A 和 B 轮流操作,A 是先手,A 希望最大化最后形成的数字,B 希望最小化最后形成的数字。输出最终形成的数字的十进制形式对 10000000091000000009 取余的结果。

思路

A 显然会拿所有可以移除的正方形中最大的那一个,B 显然拿可以移除的正方形中最小的那一个。

一个正方形是否可以移除,只与其周边的七个正方形有关。我们可以写一个 check 函数判断一个正方形是否可以被移除。因为下标范围极大,用数组模拟不太合适,可以用 STL 中的 map 存储每个位置上的正方形的编号。

我们可以首先将每个可以被移除的方块放进堆里,就可以快速找到当前所有合法选择中的最优选择,但是一个正方形可能会因为其他正方形被移除而变得不能被移除,所以需要开个标记数组记录每个正方形是否可以被移除。一个正方形被移除之后也只会影响其周围七个正方形能否被移除的状态,暴力判断更新即可。

一个正方形被修改是否可以被移除的状态为常数次,每次堆找最优解时间复杂度为 loglog 级别,所以总体复杂度 O(nlogn)O(nlogn)

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
using namespace std;
using LL=long long;
const int N=500001;
const LL mod=1000000009;
struct asdf{
	int x,y;
}a[N];
int m,flg[N];
map<LL,int> st;
LL ans;
priority_queue<int> maxx;
priority_queue<int,vector<int>,greater<int>> minn;
LL mg(int a,int b) {return 1000000005ll*a+b;}
int A,B,C,D,E,F,G;
bool check(asdf c)
{
	A=st[mg(c.x-1,c.y+1)];
	B=st[mg(c.x,c.y+1)];
	C=st[mg(c.x+1,c.y+1)];
	D=st[mg(c.x-2,c.y)];
	E=st[mg(c.x-1,c.y)];
	F=st[mg(c.x+1,c.y)];
	G=st[mg(c.x+2,c.y)];
	if (A&&D==0&&E==0) return 0;
	if (B&&F==0&&E==0) return 0;
	if (C&&F==0&&G==0) return 0;
	return 1;
}
int dx[]={-2,-1,1,2,-1,0,1};
int dy[]={0,0,0,0,-1,-1,-1};
LL solve()
{
	int qwq=0;
	scanf("%d",&m);
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		qwq=min(qwq,a[i].x);
	}
	for (int i=1;i<=m;++i)
	{
		a[i].x-=qwq;
		st[mg(a[i].x,a[i].y)]=i;
	}
	for (int i=1;i<=m;++i)
		if (check(a[i]))
		{
			maxx.push(i),minn.push(i);
			flg[i]=1;
		}
	for (int i=0,t;i<m;++i)
	{
		if (i&1)
		{
			while ((!minn.empty())&&flg[minn.top()]!=1) minn.pop();
			t=minn.top();
			minn.pop();
		}
		else
		{
			while ((!maxx.empty())&&flg[maxx.top()]!=1) maxx.pop();
			t=maxx.top();
			maxx.pop();
		}
		ans=ans*m%mod+t-1;
		ans%=mod;
		flg[t]=2;
		st[mg(a[t].x,a[t].y)]=0;
		for (int nw,j=0;j<7;++j)
		{
			nw=st[mg(a[t].x+dx[j],a[t].y+dy[j])];
			if (!nw) continue;
			if (check(a[nw]))
			{
				if (flg[nw]==0)
				{
					flg[nw]=1;
					maxx.push(nw);
					minn.push(nw);
				}
			}  
			else if (flg[nw]==1) flg[nw]=0;
		}
	}
	cout<<ans;
	return 0;
}
int main()
{
	int T=1;
	while (T--) solve();
	return 0;
}