bzoj5027 数学题(扩欧)

这题我写了一天???求ax+by+c=0的整数解x,y在范围内的对数。首先通过扩展欧几里得算出一组解:ax+by=-c,令c=-c,则ax+by=c,显然当g=gcd(a,b)不能整除c时,方程没有整数解,直接输出0。否则,令x0,y0为ax+by=g的一组整数解,则ax+by=c的一组整数解为x0=x0/g*c,y0=y0*g/c。不难发现,其他的解为x+-k*dx,y+-k*dy。因此我们以这组解为0时刻,推算出x在范围内的始末时刻xt1,xt2,y在范围内的始末时刻yt1,yt2,即可算出解的个数。(注意讨论dx,dy的正负性)tips:注意特判0的情况。

#include 
using namespace std;
#define N 10010
#define inf 0x3f3f3f3f
#define ll long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int exgcd(int a,int b,ll &x,ll &y){
    if(!b){x=1;y=0;return a;}
    int res=exgcd(b,a%b,x,y);
    ll t=x;x=y;y=t-a/b*y;return res;
}
int main(){
//  freopen("a.in","r",stdin);
    int a,b,c,x1,y1,x2,y2;
    a=read();b=read();c=read();c=-c;
    x1=read();x2=read();y1=read();y2=read();
    if(a==0&&b==0){
        if(c==0) printf("%lld\n",(ll)(x2-x1+1)*(y2-y1+1));
        else puts("0");return 0;
    }if(a==0){
        if(c%b) return puts("0"),0;
        if(c/b>=y1&&c/b<=y2) printf("%d\n",x2-x1+1);
        else puts("0");return 0;
    }if(b==0){
        if(c%a) return puts("0"),0;
        if(c/a>=x1&&c/a<=x2) printf("%d\n",y2-y1+1);
        else puts("0");return 0;
    }
    ll x0,y0;int g=exgcd(a,b,x0,y0);if(c%g) return puts("0"),0;
    x0=x0*c/g;y0=y0*c/g;int dx=b/g,dy=-a/g;int xt1,xt2,yt1,yt2;
    if(dx>0) xt1=ceil((double)(x1-x0)/dx),xt2=floor((double)(x2-x0)/dx);
    if(dx<0) xt1=ceil((double)(x2-x0)/dx),xt2=floor((double)(x1-x0)/dx);
    if(dy>0) yt1=ceil((double)(y1-y0)/dy),yt2=floor((double)(y2-y0)/dy);
    if(dy<0) yt1=ceil((double)(y2-y0)/dy),yt2=floor((double)(y1-y0)/dy);
    printf("%d\n",max(0,min(xt2,yt2)-max(xt1,yt1)+1));
    return 0;
}

你可能感兴趣的:(bzoj,扩展欧几里得算法)