您的位置:首页 > 其它

扩展欧几里德--解的个数

2016-02-02 19:21 239 查看
[b]解的个数[/b]

已知整数x,y满足如下面的条件:

  ax+by+c = 0

  p<=x<=q

  r<=y<=s

求满足这些条件的x,y的个数。

输入描述 Input Description

第一行有一个整数n(n<=10),表示有n个任务。n<=10

以下有n行,每行有7个整数,分别为:a,b,c,p,q,r,s。均不超过108。

输出描述

共n行,第i行是第i个任务的解的个数。

样例输入

2

2 3 -7 0 10 0 10

1 1 1 -10 10 -9 9

样例输出

1

19

#include<cstdio>
#include<cmath>
int x,y,a,b,c,n,g;
long long ans,p,q,r,s;
int exgcd(int a,int b,int *x,int *y)//拓展欧几里德;
{
if(b==0){*x=1;*y=0;return a;}
int d=exgcd(b,a%b,x,y);
int z=*x;*x=*y;*y=z-*y*(a/b);
return d;
}
void zhao1(int x,int y)
{
if((x<=q)&&(x>=p)&&(y>=r)&&(y<=s))ans++;
if(x<=q){
if(b/g>0){x+=b/g;y-=a/g;zhao1(x,y);}//别把zhao1 放外面,b/g=0时会被卡挂了;
else if(b/g<0){x-=b/g;y+=a/g;zhao1(x,y);}
}
}
void zhao2(int x,int y)
{
if((x<=q)&&(x>=p)&&(y>=r)&&(y<=s))ans++;
if (x>=p){
if(b/g>0){x-=b/g;y+=a/g;zhao2(x,y);}
else if(b/g<0){x+=b/g;y-=a/g;zhao2(x,y);}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
ans=0;
scanf("%d%d%d%I64d%I64d%I64d%I64d",&a,&b,&c,&p,&q,&r,&s);
if(s<r||q<p){printf("%I64d\n",ans);continue;}//x或y的可行域不存在时,结果为0;
if(a==0&&b==0&&c==0) //a,b,c均为0时 ,x,y可以是任意值;
{s=s-r+1;q=q-p+1;ans=q*s;printf("%I64d\n",ans);continue;}
if(a==0&&b==0&&c!=0) //a=b=0,c!=0时 ,无解;
{printf("%I64d\n",ans);continue;}
c=-c;                //将c调到等号右边;
g=exgcd(a,b,&x,&y);  //找到a,b的最大公因数;并且找到一组ax+by=1的一组解;
x*=c/g;y*=c/g;       //得到ax+by=c时 的一组解;
if(a*x+b*y!=c)       //等号可能不成立,例2 0 1 ;
{ans=0;printf("%ld\n",ans);continue;}
zhao1(x,y);          //分别向x变大和变小的方向找在[p,q] 之间的解;
zhao2(x,y);
if((x<=q)&&(x>=p)&&(y>=r)&&(y<=s)) ans-=1;//x,y符合要求时,两次递归多加了一次;
printf("%I64d\n",ans);
}
return 0;
}


View Code

//自认为要懂扩展欧几里德有点难,偷个懒,背个代码。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: