题目背景
某个夏天,18071 号工作室的 staff 集体转业了。辗转至年末,天依终于在 40312 号工作室拉到了合作。但是……看着编号的差距,按时到班可不是一件容易的事情。
七点半,闹铃声响起,早高峰即将迎接起床气!
题目描述
天依住在的城市像一个无穷大的曼哈顿。如果把城市地图放在平面直角坐标系中,任何一个整点 (x,y)(x,y)(x,y) 都是一个十字路口。天依家门口的十字路口为 (0,0)(0,0)(0,0),天依需要从这里出发,尽快抵达工作室所在的十字路口 (a,b)(a,b)(a,b)。每分钟,天依可以从她所在的十字路口 (x,y)(x,y)(x,y) 移动至 (x+1,y)(x+1,y)(x+1,y),(x−1,y)(x-1,y)(x−1,y),(x,y+1)(x,y+1)(x,y+1) 或者 (x,y−1)(x,y-1)(x,y−1)。
天依怎么会走路上班呢?她可以使用一辆很快很邪门的破自行车!骑上它,天依可以从 (x,y)(x,y)(x,y) 瞬间冲到 (x+l,y)(x+l,y)(x+l,y),(x,y+l)(x,y+l)(x,y+l),(x−l,y)(x-l,y)(x−l,y),(x,y−l)(x,y-l)(x,y−l) 四个位置中的一个,不花费任何时间。但为了避免破自行车散架,天依最多使用 kkk 次自行车。
那么,在破自行车的助力下,天依至少需要多少时间才能从 (0,0)(0,0)(0,0) 出发到达 (a,b)(a,b)(a,b) 呢?
因为工作室经常搬家,所以有多组测试数据。
输入格式
第一行一个整数 TTT,表示测试数据组数。
接下来 TTT 行,每行四个整数 a,b,k,la,b,k,la,b,k,l,分别表示工作室所在的十字路口的横纵坐标,自行车的使用次数限制和自行车的移动距离。
输出格式
输出 TTT 行,第 iii 行一个整数,表示第 iii 组数据中到达工作室的最小时间。
输入输出样例 #1
输入 #1
3
4 5 3 2
1 1 4 5
8 8 4 8
输出 #1
3
2
0
说明/提示
样例解释:
我们使用 >>> 表示猛冲,→\to→ 表示行走。
对于样例一,一种可能的移动方式是:(0,0)>(2,0)→(3,0)→(4,0)→(4,1)>(4,3)>(4,5)(0,0)>(2,0)\to(3,0)\to(4,0)\to(4,1)>(4,3)>(4,5)(0,0)>(2,0)→(3,0)→(4,0)→(4,1)>(4,3)>(4,5)。
对于样例二,一种可能的移动方式是:(0,0)→(0,1)→(1,1)(0,0)\to(0,1)\to(1,1)(0,0)→(0,1)→(1,1)。
对于样例三,一种可能的移动方式是:(0,0)>(0,8)>(8,8)(0,0)>(0,8)>(8,8)(0,0)>(0,8)>(8,8)。
数据规模与约定
本题采用捆绑测试。 仅当你通过了该子任务的全部测试数据才能获得该子任务的分值。
对于 100%100\%100% 的数据,1≤T≤1051 \leq T \leq 10^51≤T≤105,0≤a,b,k,l≤1090 \leq a,b,k,l\leq 10^{9}0≤a,b,k,l≤109。
对于不同的子任务,作如下约定:
子任务编号 | TTT | a,b,la,b,la,b,l | kkk | 特殊性质 | 子任务分值 |
---|---|---|---|---|---|
111 | ≤105\le10^5≤105 | ≤109\le10^9≤109 | =0=0=0 | 无 | 151515 |
222 | ≤10\le10≤10 | ≤10\le10≤10 | ≤10\le10≤10 | 无 | 101010 |
333 | ≤10\le10≤10 | ≤109\le10^9≤109 | ≤20\le20≤20 | 无 | 151515 |
444 | ≤10\le10≤10 | ≤109\le10^9≤109 | ≤103\le10^3≤103 | 无 | 202020 |
555 | ≤105\le10^5≤105 | ≤109\le10^9≤109 | ≤109\le10^9≤109 | a,b≤la,b\le la,b≤l | 151515 |
666 | ≤105\le10^5≤105 | ≤109\le10^9≤109 | ≤109\le10^9≤109 | 无 | 252525 |
贪心算法
思路:移动的每一步尽量使用破自行车猛冲。
如果没有自行车,那所需时间就是a+b。
横纵方向,先任意选择一个方向尽量使用破自行车猛冲,然后再换方向尽量使用破自行车猛冲。
横纵都冲完后,已经是最靠近(a,b)点的位置了,然后再判断要不要冲出(a,b)之外。
例如当目标点为 (5,5),l=3时,按照我们已有的策略我们会先移动到 (3,3),再一步一步走过去,花费 4 分钟;但其实可以先移动到 (6,6)再走过去,花费 2 分钟。
代码如下
#include<iostream>
using namespace std;
int T,a,b,k,l,ans1,ans2;
//ans1接收横向所需时间,ans2接收纵向所需时间
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
/*下面两行代码绝对不能放在这,如果起初l==0,除数为0会报错,显示RE
int x=a/l;
int y=b/l;
*/
cin>>T;
while(T)
{
cin>>a>>b>>k>>l;
if(l==0)
{
cout<<a+b<<'\n';
T--;//一定要在这里有个T--,因为这里也处理了一组数据
continue;
}
int x=a/l;//横向能冲的最大次数
int y=b/l;//纵向能冲的最大次数
if(k>=x)
{
k-=x;
ans1=a-x*l;
}
else
{
ans1=a-k*l;
k=0;
}
if(k>=y)
{
k-=y;
ans2=b-y*l;
}
else
{
ans2=b-k*l;
k=0;
}
//判断需不需要冲到(a,b)外面去
if(ans1>l/2&&ans2>l/2&&ans2>ans1&&k)
{
ans2=l-ans2;
k--;
}
if(ans1>l/2&&k)
{
ans1=l-ans1;
k--;
}
if(ans2>l/2&&k)
{
ans2=l-ans2;
k--;
}
T--;
cout<<ans1+ans2<<'\n';
}
return 0;
}