题解

cookiebus 2023-08-12 20:43:48 2 返回题目

原题链接:https://codeforces.com/gym/102803/problem/L

考虑把数对对应到平面直角坐标系上的坐标,那么四个操作分别对应向右、上、左、下。点的顺序的第一关键字显然是到 ​ 的曼哈顿距离,也就是所在的圈数。对于距离相同的点,其实就是把原点到它的路径写成包含“右上左下”的字符串,然后取字典序最小的一种,不同点的顺序就是这个字符串的字典序比较。

那么只要是带有“右”就按谁右多排序,不带右的就按谁上多排序,不带右和上的就按谁左多排序。

把这个规律画在图上大概就是:每一圈右半边从右到左上下震荡,左半边(包括正中间)就是顺时针转过来。就像下图:

所以从坐标找自然数只需要找到它在第几圈然后分类讨论左右即可。自然数找坐标需要开一下根号,这个注意不要出精度问题。剩下的就是代码实现的细节,记得开 long long。

#include <cstdio>
#include <cmath>
typedef long long ll;
ll abs(ll x) {return x > 0 ? x : -x; }
ll x, y, id;
void work1() {
	scanf("%lld%lld", &x, &y);
	ll c = abs(x) + abs(y);
	if (c == 0) {puts("0"); return; }
	ll p = 2*(c-1)*c;
	if (x > 0) id = p + 2*(c-x) + (y<=0);
	else id = p + 3*c - y;
	printf("%lld\n", id);
}
void work2() {
	scanf("%lld", &id);
	if (id == 0) {puts("0 0"); return; }
	ll c = sqrtl(id/2) + 10;
	while (2*(c-1)*c >= id) c--;
	ll p = 2*(c-1)*c;
	if (id-p < 2*c) {
		x = c-(id-p)/2;
		y = c-x;
		if ((id-p) & 1) y = -y;
	} else {
		y = 3*c-(id-p);
		x = -(c-abs(y));
	}
	printf("%lld %lld\n", x, y);
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	while (n--) work1();
	while (m--) work2();
}
{{ vote && vote.total.up }}