ABC135E Golf 题解

一道还行的构造题。
题目大意:一开始你在初始点 \((0,0)\),每次可以跳的曼哈顿距离为 \(k\),输出抵达 \((x,y)\) 跳的最少次数并且输出方案。
首先发现 \(x\)\(y\) 可正可负,不如把 \(x\)\(y\) 都取绝对值,在之后输出时携带符号输出即可。
因为每次的操作相当于把 \(k\) 瓜分成 \(x\)\(y\)。先考虑如果 \(k\) 是奇数那么只能拆成奇数和偶数,可以通过调控 \(k\) 的数量来构造答案。如果 \(k\) 是偶数 \(x+y\) 是偶数,只要把 \(k\) 拆成两个偶数或者奇数也是能做到的。只有 \(k\) 是偶数并且 \(x+y\) 是奇数时无解。
设答案为 \(n\),在 \(x\) 轴和 \(y\) 轴上的正向移动距离为 \(a\),反向移动距离为 \(b\),那么 \(x+y\le n\times k\)\((n\times k-x-y)\mod2=0\),这个不好解,但是 \(x\)\(y\) 值域不大所以直接枚举 \(n\) 的值就行。\(a+b=n\times k\)\(a-b=x+y\) 解出 \(a=\dfrac{n\times k+x+y}2\)\(b=\dfrac{n\times k-x-y}2\)
那就直接考虑在前进时的 \(3\) 个情况即可:(这里的 \(b\) 会随着逆向移动的距离而减小)

  • \(b\gt k\),选择 \(x\)\(y\) 里当前位置距离最终位置比较近的一个,逆向移动 \(k\)
  • \(b\leq k\),选择 \(x\)\(y\) 里当前位置距离最终位置比较近的一个,逆向移动 \(b\),另一个移动 \(k-b\)
  • \(b=0\),任意把 \(x\)\(y\) 推进,最艰难的时候过去了,可以随便放保证了。

放个代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cassert>
#define siz(x) int((x).size())
#define cauto const auto
#define all(x) x.begin(),x.end()
using std::cin;using std::cout;
using loli=long long;
using venti=__int128_t;
using pii=std::pair<int,int>;
int n=2,k,x,y;
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	std::ios::sync_with_stdio(false);cin.tie(nullptr);
	cin>>k>>x>>y;
	int opx=x/abs(x),opy=y/abs(y);x*=opx,y*=opy;
	if(x+y==k)return cout<<"1\n"<<x*opx<<' '<<y*opy,0;
	if(k%2==0&&(x+y)%2==1)return cout<<"-1",0;
	for(;n*k<x+y||(n*k-x-y)%2;)n++;
	cout<<n<<'\n';
	int b=(n*k-x-y)/2;
	for(int nx=0,ny=0;n--;cout<<nx*opx<<' '<<ny*opy<<'\n')
		if(b){
			if(b>=k){if(x-nx<y-ny)nx-=k;else ny-=k;b-=k;}
			else{if(x-nx<y-ny)nx-=b,ny+=k-b;else ny-=b,nx+=k-b;b=0;}
		}else{if(nx<x){if(x-nx>=k)nx+=k;else ny+=k-x+nx,nx=x;}else ny+=k;}
	return 0;
}
posted @ 2022-07-05 08:47  蒟酱  阅读(59)  评论(0编辑  收藏  举报