[codeforces 1293D] Aroma's Search 曼哈顿距离

[codeforces 1293D] Aroma's Search 曼哈顿距离

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址https://codeforces.com/contest/1293/problem/D

Problem Lang Verdict Time Memory
D - Aroma's Search GNU C++11 Accepted 31 ms 0 KB

//思路同此文https://blog.csdn.net/weixin_44178736/article/details/104061893

题意:
给x[0],y[0],ax,ay,bx,by
其他每个点的坐标为:
x[i]=x[i-1]*ax+bx;
y[i]=y[i-1]*ay+by;
利用这个公式可以在二维平面衍生出无数的点

给起点xs,ys和时间t,每单位时间可以向四个方向任意走一步
问t步之内最多经过多少个不同的点
思路:
解题的关键点点在于题目的数据范围:
x0, y0, ax, ay, bx, by (1≤x0,y0≤10^16, 2≤ax,ay≤100, 0≤bx,by≤10^16)
xs, ys, t (1≤xs,ys,t≤10^16)

因为ax,ay>=2,bx,by>=0而公式:
x[i]=x[i-1]*ax+bx;
y[i]=y[i-1]*ay+by;

可以发现每个点的横纵坐标至少是上一个坐标的两倍(因为乘上了ax,bx,至少为2)
所以横纵坐标的增长至少是2的指数级别,而2^64已经超过题目的t范围1e16了
可以想到可以走的点的数量最多就60个左右,再后面是不可能走到的没有意义

所以利用公式先不断求点坐标,求出的坐标超过可达范围就停止

1.x和y都是一次函数增长且斜率为正,显然越后面的点越在右上方
2.一个点走到另一个点的花费的步数是曼哈顿距离
设d(i,j)表示点i到j的曼哈顿距离
由1,2可推出一个重要结论:
d(i,i+1)+d(i+1,i+2)=d(i,i+2)

上式即X(i+1)-Xi+Y(i+1)-Yi+X(i+2)-X(i+1)+Y(i+2)-Y(i+1)=X(i+2)-Xi+Y(i+2)-Yi

由1可以想到点的位置近似是一条直线,
因此走的时候肯定照着顺序走过去而不是无序乱走
因为点最多60个,直接O(n^2)枚举要走的点的区间(枚举左右端点)
然后路径方向有两种:左端点->右端点,右端点->左端点
这两种路径花费的步数是一样的,但是题目要求从起点xs,ys开始走
所以所需时间time=min(起点到左端点,起点到右端点)+d(左端点,右端点)
如果时间time<=t则可行,更新ans为max(ans,区间长度)
#include <stdio.h>
#define LL long long
LL x[65],y[65],ax,ay,bx,by,xs,ys,t,cnt=0;
const LL INF=1e16+1;
LL min(LL a,LL b){
	return a<b?a:b;
}
LL max(LL a,LL b){
	return a>b?a:b;
}
LL abs(LL a){
	return a>=0?a:-a;
}
int main(){
	LL i,j,ans=0;
	scanf("%lld%lld%lld%lld%lld%lld",&x[0],&y[0],&ax,&ay,&bx,&by);
	while(x[cnt]<INF&&y[cnt]<INF)
		cnt++,x[cnt]=ax*x[cnt-1]+bx,y[cnt]=ay*y[cnt-1]+by;
	scanf("%lld%lld%lld",&xs,&ys,&t);
	for(i=0;i<=cnt;i++)
		for(j=i;j<=cnt;j++){
			LL tot=min(abs(xs-x[i])+abs(ys-y[i]),abs(xs-x[j])+abs(ys-y[j]));
			tot+=x[j]-x[i]+y[j]-y[i];
			if(tot<=t)ans=max(ans,j-i+1);
		}
	printf("%lld\n",ans);
	return 0;
}
发布了487 篇原创文章 · 获赞 516 · 访问量 43万+

猜你喜欢

转载自blog.csdn.net/mrcrack/article/details/104084580