SGU 141 Jumping Joe(扩展欧几里得)
2016-04-16 18:58
375 查看
Description
给出x1,x2,p,k,求一组非负整数解(p1,n1,p2,n2)满足:
p1+n1+p2+n2=k,(p1-n1)*x1+(p2-n2)*x2=p
Input
四个整数x1,x2,p,k(0< x1,x2< 40000,-40000< p< 40000,0<=k< 200000000)
Output
如果存在一组非负整数解则输出YES以及这组解,否则输出NO
Sample Input
2 3 -1 12
Sample Output
YES
1 0 5 6
Solution
令x=p1-n1,y=p2-n2,首先用扩展欧几里得求出x1*x+x2*y=g的一组解(x,y),其中g=gcd(x1,x2)
令x=x*p/g,y=y*p/g,dx=x2/g,dy=x1/g,则通解为X=x+dx*k,Y=y-dy*k
进而可以算出使得abs(X)+abs(Y)最小的X和Y
若abs(X)+abs(Y)>K则无解,因为此时的X和Y是最小需要的步数
若K-abs(X)-abs(Y)为偶数,则将这些剩下的步数分为两半,来回各走一半就可解决
若K-abs(X)-abs(Y)为奇数,那么我们需要通过加减dx和dy使得K-abs(X)-abs(Y)为偶数,此时dx+dy为偶数时无解,否则,X和Y再加减或减加一次dx和dy就可以改变K-abs(X)-abs(Y)的奇偶性
Code
给出x1,x2,p,k,求一组非负整数解(p1,n1,p2,n2)满足:
p1+n1+p2+n2=k,(p1-n1)*x1+(p2-n2)*x2=p
Input
四个整数x1,x2,p,k(0< x1,x2< 40000,-40000< p< 40000,0<=k< 200000000)
Output
如果存在一组非负整数解则输出YES以及这组解,否则输出NO
Sample Input
2 3 -1 12
Sample Output
YES
1 0 5 6
Solution
令x=p1-n1,y=p2-n2,首先用扩展欧几里得求出x1*x+x2*y=g的一组解(x,y),其中g=gcd(x1,x2)
令x=x*p/g,y=y*p/g,dx=x2/g,dy=x1/g,则通解为X=x+dx*k,Y=y-dy*k
进而可以算出使得abs(X)+abs(Y)最小的X和Y
若abs(X)+abs(Y)>K则无解,因为此时的X和Y是最小需要的步数
若K-abs(X)-abs(Y)为偶数,则将这些剩下的步数分为两半,来回各走一半就可解决
若K-abs(X)-abs(Y)为奇数,那么我们需要通过加减dx和dy使得K-abs(X)-abs(Y)为偶数,此时dx+dy为偶数时无解,否则,X和Y再加减或减加一次dx和dy就可以改变K-abs(X)-abs(Y)的奇偶性
Code
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; ll extend_gcd(ll a,ll b,ll &x,ll &y) { ll d=a; if(b!=0) { d=extend_gcd(b,a%b,y,x); y-=(a/b)*x; } else { x=1; y=0; } return d; } int main() { ll x1,x2,g,p,k,p1,n1,p2,n2; scanf("%lld%lld%lld%lld",&x1,&x2,&p,&k); g=extend_gcd(x1,x2,p1,p2); if(p%g) { printf("NO\n"); return 0; } ll dx=x2/g,dy=x1/g; p1*=p/g,p2*=p/g; while(abs(p1+dx)+abs(p2-dy)<abs(p1)+abs(p2))p1+=dx,p2-=dy; while(abs(p1-dx)+abs(p2+dy)<abs(p1)+abs(p2))p1-=dx,p2+=dy; if(abs(p1)+abs(p2)>k) { printf("NO\n"); return 0; } n1=n2=0; ll last=k-abs(p1)-abs(p2); if(last%2==0) { if(p1<0)n1=-p1,p1=0; if(p2<0)n2=-p2,p2=0; p1+=last/2,n1+=last/2; } else { if((dx+dy)%2==0) { printf("NO\n"); return 0; } if(abs(p1+dx)+abs(p2-dy)<abs(p1-dx)+abs(p2+dy))p1+=dx,p2-=dy; else p1-=dx,p2+=dy; if(abs(p1)+abs(p2)>k) { printf("NO\n"); return 0; } last=k-abs(p1)-abs(p2); if(p1<0)n1=-p1,p1=0; if(p2<0)n2=-p2,p2=0; p1+=last/2,n1+=last/2; } printf("YES\n"); printf("%lld %lld %lld %lld\n",p1,n1,p2,n2); return 0; }
相关文章推荐
- Linux 目录结构
- Java中equals和==的区别
- 13.——常用API
- 工程项目前出现红色感叹号原因
- 【matlab】:利用matlab实现QQ的一个图片显示变色功能
- 12.--基本异常处理
- filter的生命周期
- Qt学习记录--02 Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)
- JAVA——普通代码块、构造代码块、静态代码块
- 从vs2010的UnitTestFramework类库提取私有方法反射调用的方法
- QT程序打包成EXE
- Android 开源图表库 ------ MPAndroidChart
- Unity3d的Mono编辑不了的问题
- Java基础-环境变量设置及Java命令行使用 - 史上最全
- 查询出每一个雇员的姓名,工资,部门名称,工资在公司的等级及其领导的姓名,领导的工资,以及领导所相应的等级
- Hibernate Validator验证框架中@NotEmpty、@NotBlank、@NotNull 的区别
- jQuery中:first,:first-child,first()的使用区别
- opengl es 2.0 3.0 MVP矩阵计算
- Android ActionBar上不显示icon的问题
- BZOJ 4443: [Scoi2015]小凸玩矩阵 最大流