题目来源: CodeForces
基准时间限制:10 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
收藏
关注
瓦西亚和皮台亚摆放了m个方块。方块被编号为0到m-1(每个号码出现恰好一次)。现在建立一个座标系OX表示地面,OY的方向是竖直向上的。每一方块的左下角有一个座标而且是整点座标。
摆放好的方块一定要是稳定的。稳定的含意是每一个不在地面上的方块在他的下面至少有一个方块与他相接触。可以是共边,也可以是共点的。也就是说如果方块座标为(x,y),要么y=0,或者存在一个方块的座标为(x-1,y-1)或者 (x,y-1) 或者 (x+1,y-1)。
现在瓦西亚和皮台亚要轮流把这些方块一个个拆下来。按照拆下来的顺序从左到右摆成一行,那么方块上面的编号就会组成一个m进制的数字。
拆的过程中,要始终保持剩下的方块稳定。瓦西亚想要最终的数字尽可能大,而皮台亚想要尽可能小,瓦西亚先开始拆。
请帮助计算一下最终形成的数字是多少,结果比较大,输出对 109+9 取余后的结果。
样例解释:
先拿(0,1)编号为2
再拿(2,1)编号为0
再拿(1,0)编号为1
最后形成的数字是201,转成10进制是19。
Input
单组测试数据。 第一行有一个整数 m (2≤m≤10^5)。 接下来m行,每一行有一个方块的座标xi,yi (-10^9≤xi≤10^9, 0≤yi≤10^9),第i个的编号为i。i从0开始。 输入保证刚开始的摆放是稳定的,而且没有两个方块的座标是一样的。
Output
输出结果占一行。
Input示例
样例输入1 3 2 1 1 0 0 1
Output示例
样例输出1 19
题解:搞2个优先队列,一个从大到小排序,一个从小到大,瓦西亚从第一个队列中取,皮台亚从第二个队列中取,数字用完后标记vis不再被第二次使用,需要注意的是,取出一个方块后会对周围的有影响,需要更新周围方块的状态,即有些方块可能会变得不能被取出来,有些方块可能变得可以被取出来了。
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;
const int mod = 1e9 + 9;
vector<PII>v[MX];
vector<int>vx[MX], vid[MX];
vector<int>up[MX], d[MX];
bool vis[MX], can[MX];
priority_queue<int>q1;
priority_queue<int, vector<int>, greater<int> >q2;
bool check(vector<int>& u) {
rep(i, 0, u.size()) if(d[u[i]].size() == 1) return 0;
return 1;
}
void modify1(int x) {
rep(i, 0, up[x].size()) {
int y = up[x][i];
d[y].erase(find(d[y].begin(), d[y].end(), x));
if(!vis[y] && d[y].size() == 1) can[d[y][0]] = 0;
}
}
void modify2(int x) {
rep(i, 0, d[x].size()) {
int y = d[x][i];
up[y].erase(find(up[y].begin(), up[y].end(), x));
if(!vis[y] && check(up[y])) q1.push(y), q2.push(y), can[y] = 1;
}
}
int main() {
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int n, x, y, id; cin >> n;
rep(i, 0, n) {
cin >> x >> y;
v[y].push_back(PII(x, i));
}
rep(i, 0, n) if(!v[i].empty()) sort(v[i].begin(), v[i].end());
rep(i, 0, n) rep(j, 0, v[i].size()) vx[i].push_back(v[i][j].x), vid[i].push_back(v[i][j].y);
rep(i, 0, n) rep(j, 0, v[i].size()) {
x = v[i][j].x, id = v[i][j].y;
if(!vx[i + 1].empty()) {
int l = lower_bound(vx[i + 1].begin(), vx[i + 1].end(), x - 1) - vx[i + 1].begin();
int r = upper_bound(vx[i + 1].begin(), vx[i + 1].end(), x + 1) - vx[i + 1].begin();
rep(k, l, r) up[id].push_back(vid[i + 1][k]);
rep(k, l, r) d[vid[i + 1][k]].push_back(id);
}
}
rep(i, 0, n) if(up[i].empty() || check(up[i])) q1.push(i), q2.push(i), can[i] = 1;
ll ans = 0;
rep(i, 0, n) {
if(i % 2 == 0) {
while(!q1.empty()) {
x = q1.top(); q1.pop();
if(vis[x] || !can[x]) continue;
vis[x] = 1;
ans = (ans * n + x) % mod;
modify1(x);
modify2(x);
break;
}
} else {
while(!q2.empty()) {
x = q2.top(); q2.pop();
if(vis[x] || !can[x]) continue;
vis[x] = 1;
ans = (ans * n + x) % mod;
modify1(x);
modify2(x);
break;
}
}
}
cout << ans << endl;
return 0;
}