LightOJ - 1306 Solutions to an Equation

题目大意:给你一个方程ax+by+c=0(x1<=x<=x2&&y1<=y<=y2)

求其整数解个数

具体思路:扩展欧几里得求一个特解,然后求一下x和y的最少变化量,

然后求出当x1<=x<=x2,与其对应的y的范围,和y1<=y<=y2做一个并,在算一下有几个解就好了

花絮:一开始我发现x=x0+xx*t(x0为特解,xx为最少变化量)y=y0-yy*t,并试图求出t的范围,wa了几发之后发现有许多+1-1的奇怪地方需要处理,于是果断换了一个做法

        结果却还是wa,通过一些特殊手段发现好像是我为了把方程变为ax+by=c,我把读入的c取反,但前面的特判写的比较早~~~

 

扩展欧几里得是什么勒?

欧几里得算法可以求最大公约数

int gcd(int a,int b){if(b==0)return a;else return gcd(b,a%b);}

然后扩展欧几里得可以求ax+by=gcd(a,b)的一组解

怎么求的呢?

因为gcd(a,b)=gcd(b,a%b)

所以ax+by=gcd(a,b)可以变为

b*x1+(a%b)*y1=gcd(b,a%b)=ax+by

然后一顿公式变形

b*x1+(a%b)*y1=b*x1+(a-[a/b]*b)*y1([]为下取整)

=b*x1+(a-[a/b]*b)*y1=a*y1+b*(x1-[a/b]*y1)=ax+by

所以x=y1  y=x1-[a/b]*y1

于是可以写成这样

void exgcd(int a,int b,int& d,int& x,int & y)
{
    if(b==0)d=a,x=1,y=0;
    else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}

 

最后是AC代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long 
using namespace std;
int T;
int gcd(int a,int b){if(b==0)return a;else return gcd(b,a%b);}
void exgcd(int a,int b,int& d,int& x,int & y)
{
    if(b==0)d=a,x=1,y=0;
    else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
main()
{
    scanf("%lld",&T);
    int t;
    for (t=1;t<=T;t++)
    {
        
        int a,b,c,X1,X2,Y1,Y2;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&X1,&X2,&Y1,&Y2);c=-c;
        printf("Case %lld: ",t);
        if(a==0&&b==0)
        {
            if(c==0) printf("%lld\n",(Y2-Y1+1)*(X2-X1+1));else puts("0");
            continue;  
        }
        else if(a==0)
        {
            if(c%b!=0) puts("0");
            else
            {
                int z=c/b;
                if(z>=Y1&&z<=Y2) printf("%lld\n",(X2-X1+1));else puts("0");
            }
            continue;
        }
        else if(b==0)
        {
            int z=c/a;
            if(c%a!=0) puts("0");
            else if(z>=X1&&z<=X2) printf("%lld\n",(Y2-Y1+1));
            else puts("0");
            continue;
        }
        int g=gcd(a,b);
        if(c%g)
        {
            puts("0");
            continue;
        }
        int x,y;
        exgcd(a,b,g,x,y);
        x=x*(c/g),y=y*(c/g);
        int xx=b/g,yy=a/g,Ymn,Ymx;
        X1=((x-X1)%xx+abs(xx))%abs(xx)+X1;
        X2=((x-X2)%xx-abs(xx))%abs(xx)+X2;
        if(X1>X2){printf("0\n");continue;}
        
        Ymn=(-yy)*((X1-x)/xx)+y;
        Ymx=(-yy)*((X2-x)/xx)+y;
        if(Ymn>Ymx)swap(Ymn,Ymx);
        Y1=max(Y1,Ymn);
        Y2=min(Y2,Ymx);
        Y1=((y-Y1)%yy+abs(yy))%abs(yy)+Y1;
        Y2=((y-Y2)%yy-abs(yy))%abs(yy)+Y2;
        if(Y1>Y2)puts("0");else printf("%lld\n",(Y2-Y1)/abs(yy)+1);
    }
    return 0;
}

 


posted @ 2017-10-30 22:27  橙子用户  阅读(246)  评论(0编辑  收藏  举报