SGU 141 Jumping Joe(扩展欧几里得)
2014-01-14 18:09
267 查看
题意:一只青蛙在坐标轴的原点,它每次可以向左或向右跳x1或x2的距离,现在,它想跳K次恰好跳到P点,求一个跳的方案,P1为向右跳x1的次数,N1为向左跳x1的次数,P2为向右条x2的次数,P3为向左跳x2的次数。
思路:唉,对数论什么的一直没感觉啊,做了半天好不容易做出来了……首先是求一个可行解,这个简单,相当于解ax+by=c的方程,直接用扩展欧几里得就可以搞定,这里求出的x和y分别相当于P1-N1,P2-N2,剩下是怎么安排次数的问题……首先要把abs(x)+abs(y)的值变到最小,我们知道对于扩展欧几里得求出的解x0,y0来说,x=x0+k*(y0/d) y=y0-k*(x0/d)都是方程的解那么我们就可以通过这个来调整,令abs(x)+abs(y)的值最小,如果此时abs(x)+abs(y)还是大于k,那么说明无解。否则,看此时还需要走多少歩(也就是k-abs(x)+abs(y)),如果是偶数歩,那么简单,剩下的步数只要不断重复走P1,N1就行了。如果不行的话……我们知道通过上面寻找最小值的方法可以调整x和y的值,此时,如果(y0/d)和(x0/d)的奇偶性不同,那么分别对x和y增加(减少)这两个数就可以改变奇偶性了,否则就无解……
代码:
思路:唉,对数论什么的一直没感觉啊,做了半天好不容易做出来了……首先是求一个可行解,这个简单,相当于解ax+by=c的方程,直接用扩展欧几里得就可以搞定,这里求出的x和y分别相当于P1-N1,P2-N2,剩下是怎么安排次数的问题……首先要把abs(x)+abs(y)的值变到最小,我们知道对于扩展欧几里得求出的解x0,y0来说,x=x0+k*(y0/d) y=y0-k*(x0/d)都是方程的解那么我们就可以通过这个来调整,令abs(x)+abs(y)的值最小,如果此时abs(x)+abs(y)还是大于k,那么说明无解。否则,看此时还需要走多少歩(也就是k-abs(x)+abs(y)),如果是偶数歩,那么简单,剩下的步数只要不断重复走P1,N1就行了。如果不行的话……我们知道通过上面寻找最小值的方法可以调整x和y的值,此时,如果(y0/d)和(x0/d)的奇偶性不同,那么分别对x和y增加(减少)这两个数就可以改变奇偶性了,否则就无解……
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; void ext_gcd(ll a,ll b,ll & x,ll & y,ll & d) { if(b==0) { d=a;x=1;y=0; return ; } ext_gcd(b,a%b,y,x,d); y-=(a/b)*x; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); ll x,y,p,k,d,tmp; ll N1,N2,P1,P2,ta,tb; cin>>x>>y>>p>>k; if(p==0&&k==0) { cout<<"YES"<<endl; cout<<"0 0 0 0"<<endl; return 0; } ext_gcd(x,y,P1,P2,d); if(p%d) {cout<<"NO"<<endl;return 0;} ta=x/d;tb=y/d; P1=P1*(p/d); P2=P2*(p/d); while(abs(P1)+abs(P2)>abs(P1-tb)+abs(P2+ta)) {P1-=tb;P2+=ta;} while(abs(P1)+abs(P2)>abs(P1+tb)+abs(P2-ta)) {P1+=tb;P2-=ta;} if(abs(P1)+abs(P2)>k) { cout<<"NO"<<endl; return 0; } N1=N2=0; tmp=k-abs(P1)-abs(P2); if(tmp%2==0) { if(P1<0) swap(P1,N1),N1=-N1; if(P2<0) swap(P2,N2),N2=-N2; P1+=(tmp/2); N1+=(tmp/2); } else { if((ta+tb)%2==0) { printf("NO\n"); return 0; } else { if(abs(P1+tb)+abs(P2-ta)<abs(P1-tb)+abs(P2+ta)) { P1+=tb; P2-=ta; } else { P1-=tb; P2+=ta; } if(abs(P1)+abs(P2)>k) { printf("NO\n"); return 0; } k-=abs(P1)+abs(P2); if(P1<0) swap(P1,N1),N1=-N1; if(P2<0) swap(P2,N2),N2=-N2; P1+=(k/2); N1+=(k/2); } } cout<<"YES"<<endl; cout<<P1<<" "<<N1<<" "<<P2<<" "<<N2<<endl; return 0; }
相关文章推荐
- 开发备忘录
- CImage类库
- Opencv cvAbs函数
- LVM逻辑卷管理器
- Opencv cvAbs函数
- C++编程思想笔记
- ios_oc学习总结
- TSQL--NULL值和三值逻辑
- Cximage 切图部分代码mark
- Linux文件系统-3个重要数据结构及相互间的关系
- mysql cluster 节点增加和减少
- POJ - 1101 The Game DFS
- Android framwork cpp调用java function
- rhel 6.3 建立centos yum
- TSQL--INT转换成指定长度字符串
- 反映现实生活情感的一种艺术就是音乐
- inotify -- Linux 2.6 内核中的文件系统变化通知机制
- 基于mybatis的shard方案(分表分库、读写分离)
- 仿百度文库文档上传页面的多级联动分类选择器
- 应用jquery批量新增(一、页面新增多行)