题目链接 原网站炸了,题目都没了,又重新建的新网站
题意:
描述
全是电梯。
Philo正处于高度为0的一个平台上,在他面前的一个平面,全是上上下下的电梯。
Philo想要离开这里,请你帮帮他。
电梯世界规则:这里的电梯所能到达的层数皆为整数层,当Philo进入电梯,他只能选择上升a层或者下降b层(电梯只有这两种选择且a,b不同时为0)。对于任意整数层都有无限的电梯可乘坐(前提是Philo能够到达这一层)。
Philo在第0层,现在请你帮助Philo到达第nn层。如果可以请输出"YES",并输出他的合法的最小解。否则输出"NO"。
输入
每组测试数据输入三个整数n,a,b;
含义如题上所述
输入到文件结束;
-1e9<= n <=1e9
0<= a, b <=1e9
输出
若能够通过一定的次数使Philo到达第nn层,则先输出YES,下一行输出合法的最小解,否则输出NO.
输入样例 1
3 6 9 4 9 3
输出样例 1
YES 2 1 NO
可以看出,这其实就是解二元一次方程ax+by=n的根,那么就可以想到一个关于解这个方程的一个知识 扩展欧几里得
通过解出ax+by=gcd(a,b)的一个解来反推出原方程的解
注意一点 会爆int
代码
#include<bits/stdc++.h>
using namespace std;
long long n,a,b;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
long long r = exgcd( b , a % b , x , y);
long long t=y;
y=x-(a/b)*y;
x=t;
return r;
}
int main()
{
while(scanf("%lld%lld%lld",&n,&a,&b)!=EOF)
{
long long a1,b1;//用来处理最后的结果
b = -b;//因为b是下降的阶数
a1 = a,b1 = b;
long long x,y;
long long h=exgcd(a,b,x,y);
if(!n)
{
puts("YES");
printf("0 0\n");
}
else if( n % h ||( a==0 && n / b < 0 ) || ( b==0 && n / a <0 ) )//主要考虑这三种情况:1不能有扩展欧几里得来反推回原方程,2,斜率不存在且与x轴相交于负半轴,3,斜率为0,与y轴相交于负半轴
printf("NO\n");
else
{
printf("YES\n");
a /= h;//为了求得最小的a值用来递推x,以此求最小合法的x,下同,之所以是同时除以h是因为要保证最后 a1 * b 和a*b1的值要相等;
b /= h;
x *= ( n / h );//由扩展方程的解推回原方程;
y *= ( n / h );
if(a<0) a = -a;
if(b<0) b = -b;
if(b)//求出最小合法的x,y如果不行,进行下一个else if(a)
{
long long k1= -x / b;
if(x + k1 * b < 0) k1++;
x += k1 * b;
y=(n - a1 * x) / b1;
if(y>=0) printf("%lld %lld\n",x,y);
}
else if(a)
{
long long k1= -y /a;
if(y + k1 * a < 0) k1++;
y += k1 *a;
x=(n - b1 * y)/a1;
printf("%lld %lld\n",x,y);
}
}
}
return 0;
}