题意:http://www.lightoj.com/volume_showproblem.php?problem=1306

在范围内 求出满足ax+b*y+c=0的解    典型的扩展欧几里得

首先我们可以求出ax+by=gcd(a,b)=g的一个组解(x0,y0).而要使ax+by=c有解,必须有c%g==0.

继而可以得到ax+by=c的一个组解x1=c*x0/g , y1=c*y0/g

这样可以得到ax+by=c的通解为:

                  x=x1+b*t;//为了范围更大这里的 b=b/g;   a=a/g

                  y=y1-a*t;

表达式为 x=x0*c/g+b*t/g

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<vector>
#include<math.h>
#include<string>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define N 10006
#define Lson rood<<1
#define Rson rood<<1|1
LL exgcd(LL a,LL b,LL &x,LL &y)///扩展欧几里得 算出ax+by=gcd(a,b)的一组解
{
    if(b==0) {
        x=1;y=0;
        return a;
    }
    else {
        LL g=exgcd(b,a%b,x,y);
        LL t=x;
        x=y;
        y=t-a/b*y;
        return g;
    }
}
LL sign(LL a)
{
    if(a==0) return 0;
    return a>0?1:-1;
}
LL ceil(LL a,LL b)
{
    LL s=sign(a)*sign(b);
    return b/a+(b%a!=0&&s>0);
}
LL floor(LL a,LL b)
{
    LL s=sign(a)*sign(b);
    return b/a-(b%a!=0&&s<0);
}
int main()
{
    int T,t=1;
    scanf("%d",&T);
    while(T--)
    {
        LL a,b,c,x1,x2,y1,y2;
        scanf("%lld %lld %lld %lld %lld %lld %lld,",&a,&b,&c,&x1,&x2,&y1,&y2);
        printf("Case %d: ",t++);
        if(!a&&!b)///三个特判  a与b为0 的处理
        {
            if(c) printf("0\n");
            else printf("%lld\n",(x2-x1+1)*(y2-y1+1));
            continue;
        }
        else if(!a)
        {
            if(c%b) printf("0\n");
            else if((-c/b)>=y1&&(-c/b)<=y2) printf("%lld\n",x2-x1+1);
            else printf("0\n");
            continue;
        }
        else if(!b)
        {
            if(c%a) printf("0\n");
            else if((-c/a)>=x1&&(-c/a)<=x2) printf("%lld\n",y2-y1+1);
            else printf("0\n");
            continue;
        }   
        LL x,y;
        LL g=exgcd(a,b,x,y);
        if(c%g!=0){///求出一组解 判断是否有解
            printf("0\n");
            continue;
        }///因为是一元一次方程  需要看清是递增还是递减  然后在处理
        if(sign(g)*sign(b)<0) swap(x1,x2);
        LL k1=ceil(b,g*x1+c*x);//因为是小值 有部分已经占用 需要向上取整 
        LL k2=floor(b,g*x2+c*x);//同理 向下取整
        if(sign(-a)*sign(g)<0) swap(y1,y2);
        LL k3=ceil(-a,g*y1+c*y);
        LL k4=floor(-a,g*y2+c*y);
        k1=max(k1,k3);
        k2=min(k2,k4);
        if(k1>k2) printf("0\n");
        else printf("%lld\n",k2-k1+1);
    }
    return 0;
}

 

posted on 2017-10-19 11:50  云胡不喜。  阅读(198)  评论(0编辑  收藏  举报