类欧几里德
bzoj 2187: fraction 类欧几里德算法
题意:给你4个正整数a,b,c,d,求一个最简分数 p / q满足 a / b < p / q < c / d,若有多组解,输出q最小的一组,若仍有多组解,输出p最小的一组。
#include
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b){//求AB最大公因数
if (!b) return a;
else return gcd(b,a%b);
}
void sim(LL &a,LL &b){LL d=gcd(a,b);a/=d;b/=d;}//A,B共除GCD变互质,实即约分
void solve(LL a,LL b,LL c,LL d,LL &p,LL &q){
sim(a,b);sim(c,d);//AB,CD约分
LL x=a/b+1,y=c/d+(c%d>0)-1;//X是大于A/B的最小整数,Y是小于C/D的最大整数
if (x<=y) p=x,q=1;//X已经小于Y,注意结束语句下PQ是同时取最小值的
else if (!a) p=1,q=d/c+1;//A是0则只考虑右边即可,注意结束语句下PQ同时取最小值
else if (a<=b&&c<=d) solve(d,c,b,a,p,q),swap(p,q);//左右都是真分数,就变倒数,注意变号
else solve(a%b,b,c-d*(a/b),d,p,q),p+=q*(a/b);//假分数就式子各部分全减(a/b),如此反复
}
int main(){
LL a,b,c,d;//输入ABCD,求a / b < p / q < c / d
while (scanf("%lld%lld%lld%lld",&a,&b,&c,&d)!=EOF){
LL p,q;
solve(a,b,c,d,p,q);
printf("%lld/%lld\n",p,q);
}
}
JZOJ 3736. 【NOI2014模拟7.11】数学题(math)
#include
using namespace std;
#define LL long long
LL const Mxa=1e4,Inf=1e9;double Eps=1e-6;
LL X1,X2,Y1,Y2;
LL Dot(LL X1,LL Y1,LL X2,LL Y2){return X1*X2+Y1*Y2;}//点乘
double Abs(LL X1,LL Y1){return sqrt(X1*X1+Y1*Y1);}//求模
int main(){
double Cos,M1,M2;//余弦值,两个模
while(scanf("%lld%lld%lld%lld",&X1,&Y1,&X2,&Y2)!=EOF){
if(Dot(X1,Y1,X2,Y2)<0)X1=-X1,Y1=-Y1;//如果点乘小于零则令X1取反实即成锐角
double xx=Dot(X1,Y1,X2,Y2),x=Abs(X1,Y1),y=Abs(X2,Y2);//求出两向量点乘与模长
if(X1*Y2==X2*Y1){printf("0\n");continue;}//叉乘相等即共线直接0
while((Cos=Dot(X1,Y1,X2,Y2)/Abs(X1,Y1)/Abs(X2,Y2))>0.5){//COS值大于1/2即小于60度,就取反方向
M1=Abs(X1,Y1),M2=Abs(X2,Y2);//读出两模
if(M1>M2+Eps)swap(X1,X2),swap(Y1,Y2),swap(M1,M2);//M1模长就较换两向量的X,Y,模三个参数
LL Tmp=M2/M1;//得到模长比值
if(M2*Cos-M1*Tmp
Sample Input
3 0 1 2
6 0 4 0
Sample Output
5
0
结论1.两个向量夹角大于60度,肯定答案会取两个向量模长的较小值。
结论2. (a, b)所对应的答案,和(a, b + ka)一致,其中k为整数。