类欧几里德

类欧几里德
bzoj 2187: fraction 类欧几里德算法
题意:给你4个正整数a,b,c,d,求一个最简分数 p / q满足 a / b < p / q < c / d,若有多组解,输出q最小的一组,若仍有多组解,输出p最小的一组。

#include<bits/stdc++.h>
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<bits/stdc++.h>
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<M1*(Tmp+1)-M2*Cos)//图中CE段小于ED段
                X2-=X1,Y2-=Y1;//长边OB加一单位OA,则夹角就变大了
            else X2=-X1*(Tmp+1)+X2,Y2=-Y1*(Tmp+1)+Y2,X1=-X1,Y1=-Y1;
            //如果CE大于ED段,OB减去OD段,然后OA也取反(即使是大于60度也要是在0~90度范围内!
        }
        printf("%lld\n",min(X1*X1+Y1*Y1,X2*X2+Y2*Y2));//最后输出向量和模平方
    }
    return 0;
}

Sample Input
3 0 1 2
6 0 4 0
Sample Output
5
0
结论1.两个向量夹角大于60度,肯定答案会取两个向量模长的较小值。
在这里插入图片描述
结论2. (a, b)所对应的答案,和(a, b + ka)一致,其中k为整数。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值