Codeforces 1292B Aroma's Search(思维,曼哈顿距离)
题目大意
给出无限个点和一个长度\(t\),每个点的坐标可由前一个点计算得到,从一个点移动到另外一个点走过的长度为两点间的曼哈顿距离,问从起始坐标开始走长度\(t\)的距离最多到达多少个点。
分析
因为题中给出\(2\leq a_x , a_y以及0\leq b_x,b_y\)很显然所有的坐标都在第一象限并且是指数型增长的,并且因为\(t\leq 1e16\),所以实际能走到的点也就几十个。这么少的点数给我们暴力求解提供的可能。
再分析
我们怎样才能走最小的路径到达尽量多的点呢?很明显顺着一边走比在两边左右横跳走的路径更短,而且越靠近原点点也就越密集,那么一共有三种走法。
从起始点到达一个点,然后顺着这个点往x轴负半轴走
这样的话走过的总的路径长度就是起始点到走过的第一个点的曼哈顿距离和第一个点到最后一个点的曼哈顿距离。
从起始点到达一个点,然后顺着这个点往x轴正半轴方向走
这样的话走过的总的路径长度的计算方法与上面类似。
从起始点到达一个点,然后先往x轴负半轴方向走,走到头再往x正半轴方向走
这是我在一些博客上看见的,我感觉这种方法是不行的。因为这样路径长度就是走过的最靠近\(x\)轴负半轴的点与离这个点最远的点之间的曼哈顿距离再加上走过的第一个点到走过的的最靠近\(x\)轴负半轴的点之间的曼哈顿距离,在这之上,还要加上起始点到第一个到达的点的曼哈顿距离。如果我们直接从起始点走到离\(x\)轴负半轴最近的点然后再往\(x\)轴正半轴走显然是更优的。
具体实现
从上面的分析可以看出,我们只要枚举一个起点(不包括起始点)和一个终点,所走的路径就是起始点到起点的曼哈顿距离加上起点到终点的曼哈顿距离,而两点间的点的个数就是每种方案的答案。
代码
unll x0, y0, xs, ys, ax, ay, bx, by, t;
int main(void) {
while(cin>>x0>>y0>>ax>>ay>>bx>>by>>xs>>ys>>t) {
vector<pair<unll, unll> > e;
e.emplace_back(x0, y0);
while(x0*ax+bx<1e17 && y0*ay+by<1e17) {
x0 = x0*ax+bx;
y0 = y0*ay+by;
e.emplace_back(x0, y0);
}
int ans = 0;
for (int i = 0; i<(int)e.size(); ++i)
for (int j = 0; j<(int)e.size(); ++j)
if (llabs(e[i].first-e[j].first)+llabs(e[i].second-e[j].second)+llabs(xs-e[i].first)+llabs(ys-e[i].second)<=(unll)t)
ans = max(ans, abs(i-j)+1);
cout << ans << endl;
}
return 0;
}