数学专项number_theory:UVa 11768

这道题之前做过一次,在WA了数炮之后,就把这题放下了。

这几天找了本《数论概论》稍稍系统的学了下,今天把这题重新找了出来做一做。结果从下午3点做到晚上9点,自己手写了数据生成器和一个暴力的程序,一步一步调才把这题给AC了,实在太不容易了。

回过头来看似乎也不算太难,只不过有相当多需要注意的地方。首先将直线化成一般式,然后把所有参数都处理成整数即a*x+b*y=c的形式,然后用扩展gcd求出一个特解(这里我犯了一个错误,就是误把a、b都取了下绝对值,完全是想太多了),然后根据丢番图解线性方程的方式,在x的取值范围统计整数点数。最后需要注意特判下a或b为0的情况。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
void Read(LL &s)
{
    double t;
    scanf("%lf",&t);
    s=10*(t+0.05);
}
void gcd(LL a,LL b,LL& d,LL& x,LL& y)
{
    if(!b) {d=a;x=1;y=0;}
    else
    {
        gcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
LL x1,x2,z1,z2,a,b,c,x,y,d;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        Read(x1);Read(z1);Read(x2);Read(z2);
        if(x1==x2&&x1%10==0)
        {
            if(z1>z2) swap(z1,z2);
            double k1=floor(1.0*z1/10),k2=floor(1.0*z2/10);
            int ans=k2-k1;
            if(z1%10==0) ans++;
            printf("%d\n",ans);
            continue;
        }
        else if(x1==x2)
        {
            puts("0");continue;
        }
        if(z1==z2&&z1%10==0)
        {
            if(x1>x2) swap(x1,x2);
            double k1=floor(1.0*x1/10),k2=floor(1.0*x2/10);
            int ans=k2-k1;
            if(x1%10==0) ans++;
            printf("%d\n",ans);
            continue;
        }
        else if(z1==z2)
        {
            puts("0");continue;
        }
        a=10*(z2-z1);b=10*(x1-x2);c=x1*z2-x2*z1;
        gcd(a,b,d,x,y);
        if(c%d!=0)
        {
            puts("0");
            continue;
        }
        a/=d;b/=d;c/=d;x*=c;y*=c;
        double K1=1.0*(x1-10*x)/(b*10),K2=1.0*(x2-10*x)/(b*10);
        LL k1,k2;
        int ans=0;
        if(K1>K2)
        {
            k1=ceil(K1);
            k2=floor(K2);
        }
        else
        {
            k1=ceil(K2);
            k2=floor(K1);
        }
        for(LL i=k2;i<=k1;i++)
        {
            LL tmp=10*(x+i*b);
            if(tmp>=min(x1,x2) && tmp<=max(x1,x2)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值