题目大意: 有一张 n × m n\times m n×m 的网格图,起点为 ( s x , s y ) (sx,sy) (sx,sy),终点为 ( e x , e y ) (ex,ey) (ex,ey),有三种移动方式:1、 选择一个 k k k,移动到 ( x + k , y + k ) (x+k,y+k) (x+k,y+k),代价为 a a a;2、移动到 ( x + d , y ) (x+d,y) (x+d,y),代价为 b b b;3、移动到 ( x , y + d ) (x,y+d) (x,y+d),代价为 c c c,问能否到达终点,能的话最小代价是多少。
题解
比较显然的是操作 1 1 1 至多用一次,那么看一下用和不用哪个代价更小即可。
假如只看操作 1 1 1,那么从 ( x , y ) (x,y) (x,y) 出发能走到 ( x + 1 , y + 1 ) , ( x + 2 , y + 2 ) . . . (x+1,y+1),(x+2,y+2)... (x+1,y+1),(x+2,y+2)...,最后走回 ( x , y ) (x,y) (x,y)。这样的路径我们称之为一个循环,那么一个循环的长度就是 l c m ( n , m ) lcm(n,m) lcm(n,m),一共有 n m l c m ( n , m ) = gcd ( n , m ) \dfrac {nm} {lcm(n,m)}=\gcd(n,m) lcm(n,m)nm=gcd(n,m) 个循环。
假如 ( s x , s y ) (sx,sy) (sx,sy) 和 ( e x , e y ) (ex,ey) (ex,ey) 在同一个循环内,那么直接一次操作 1 1 1 就可以了,假如不在的话,就需要用操作 2 , 3 2,3 2,3 来跳到同一个循环内。
但是可以发现,只用其中一个操作是最优的,不需要同时用到两个操作,因为两个操作同时用的话,相当于从 ( x , y ) (x,y) (x,y) 到 ( x + d , y + d ) (x+d,y+d) (x+d,y+d),这等价于让操作 1 1 1 的 k k k 加 d d d,而这样还能让费用减少 b + c b+c b+c。
那么接下来就是考虑求出从 ( s x , s y ) (sx,sy) (sx,sy) 到 ( e x , e y ) (ex,ey) (ex,ey) 所在循环需要多少代价了,假如只用操作 2 2 2,即只更改 x x x 坐标,那么就是求出这个方程的解: s x + ( e y − s y ) + d x ≡ e x ( m o d gcd ( n , m ) ) sx+(ey-sy)+dx\equiv ex \pmod {\gcd(n,m)} sx+(ey−sy)+dx≡ex(modgcd(n,m)),转化一下就是 d x + gcd ( n , m ) y = ( e x − s x ) − ( e y − s y ) dx+\gcd(n,m)y=(ex-sx)-(ey-sy) dx+gcd(n,m)y=(ex−sx)−(ey−sy),扩欧即可。
只用操作 3 3 3 也是类似的, d x + gcd ( n , m ) y = ( e y − s y ) − ( e x − s x ) dx+\gcd(n,m)y=(ey-sy)-(ex-sx) dx+gcd(n,m)y=(ey−sy)−(ex−sx)。
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 999999999999999999ll
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)return x=1,y=0,a;
ll d=exgcd(b,a%b,y,x);
return y-=a/b*x,d;
}
ll getans(ll a,ll b,ll c,ll cost)
{
ll x,y,GCD=exgcd(a,b,x,y);
if(c%GCD)return inf;
b/=GCD;if(b<0)b=-b;
return (c/GCD*x%b+b)%b*cost;
}
ll T,n,m,d,sx,sy,ex,ey,a,b,c;
ll solve()
{
if(sx==ex&&sy==ey)return 0;
ll re=min(inf,getans(d,n,(ex-sx+n)%n,b)+getans(d,m,(ey-sy+m)%m,c));//不用操作1
ll GCD=gcd(n,m);
re=min(re,getans(d,GCD,((ex-sx+GCD)%GCD-(ey-sy+GCD)%GCD+GCD)%GCD,b)+a);
re=min(re,getans(d,GCD,((ey-sy+GCD)%GCD-(ex-sx+GCD)%GCD+GCD)%GCD,c)+a);
return re==inf?-1:re;
}
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",&n,&m,&d,&sx,&sy,&ex,&ey,&a,&b,&c);
printf("%lld\n",solve());
}
}