数论 + 扩展欧几里得 - SGU 106. The equation

简介:  The equation  Problem's Link   Mean:  给你7个数,a,b,c,x1,x2,y1,y2.求满足a*x+b*y=-c的解x满足x1= lx)    {        ans = min(rx,ry)-ma...

 The equation 

Problem's Link


 

Mean: 

给你7个数,a,b,c,x1,x2,y1,y2.求满足a*x+b*y=-c的解x满足x1<=x<=x2,y满足y1<=y<=y2.求满足条件的解的个数.

analyse:

做法是扩展欧几里德.

1.首先是欧几里德算法,欧几里德算法是用于求任意两个数的最大公约数(gcd(a,b)),

这个方法基于一个定理,gcd(a,b)=gcd(b,a % b)(a>b),%表示取模.

我们来证明上述定理,因为a>b,所以我们可以将a表示成a=kb+r,

假设gcd(a,b)=d,也就是两个数的最大公约数为d.

那么d|a,d|b,这是显然的.

又因为r=a-kb,所以d|r.

而r的值就像当于a % b,

所以gcd(a,b)=gcd(b,a%b).

2、欧几里德扩展算法。根据贝祖定理,如果gcd(a,b)=d,那么一定存在整数x,y使得a*x+b*y=gcd(a,b)=d.并且a和b的线性和都为d的整数倍.

欧几里德扩展算法就是用来求出这个线性方程的一个解的。注意,只是其中一个解.

首先设两个数aa=b,bb=a%b=a-a/b*b;

因为gcd(a,b)=gcd(b,a%b)=gcd(aa,bb).

所以aa*xx+bb*yy=gcd(aa,bb)=gcd(a,b)

我们用a和b来表示aa,bb.

所以b*xx+(a-a/b*b)yy=gcd(a,b)

a*yy+b*(xx-a/b*yy)=gcd(a,b).

对照不定方程a*x+b*y=gcd(a,b)

我们可以得到该不定方程的解为x=yy,y=xx-a/b*yy.

当我们递归上述操作时会得到b=0的情况,此时式子相当与a*xx=a,

所以此时xx=1,yy=0;以此做返回值.

 

3、对于a*x+b*y=n这个不定方程的求解。
根据贝祖定理,我们知道a*x+b*y这个不定方程的值一定是gcd(a,b)的整数倍。
那么如果n不是gcd(a,b)的倍数,该不定方程一定没有整数解。
我们先求解出gcd(a,b).
方程两边同时除以gcd(a,b).我们假设aa=a/gcd(a,b),bb=b/gcd(a,b),nn=n/gcd(a,b)
所以方程两边同时除以gcd(a,b)后,
可以得到一个方程aa*x+bb*y=nn.
并且该方程aa*x+bb*y=nn的解x,y就是a*x+b*y=n的解。
我们转化成这个方程有什么用处呢?
用处就在于gcd(aa,bb)=1.
我们只要求解出aa*x+bb*y=1的其中一个解,设这两个解为x0,y0.
那么aa*x+bb*y=nn的其中一个解解就是x0*nn,y0*nn.
接着,a*x+b*y=n的其中一个解解也就是x0*nn,y0*nn.

 

很显然,这道题目要我们求解的个数,一个解是不够的。
我们继续看a*x+b*y=n这个式子,它的一个解为x0*nn,y0*nn.我们尝试代入,得到
a*(x0*nn)+b*(y0*nn)=n.
我们会发现
a*(x0*nn+1*b)+b*(y0*nn-1*a)=n
a*(x0*nn-1*b)+b*(y0*nn+1*a)=n.
继续推广
a*(x0*nn+k*b)+b*(y0*nn-k*a)=n (k属于整数)
nn=n/gcd(a,b).
那么一个结论出来了
『x=x0*nn+k*b
y=y0*nn-k*a
k属于整数
nn=n/gcd(a,b)
x0,y0,为a/gcd(a,b)*x+b/gcd(a,b)*y=1的一个解』
为原不定方程a*x+b*y=n的所有解。

 

4、关于sgu106的求解。
sgu106与a*x+b*y=n这个不定方程求解这两个问题的不同之处就在于。
sgu106的解有取值范围。
我们把x0*nn,y0*nn看成两个常数xz,yz.
那么原方程解就变成两个一次函数
x=k*b+xz(1)
y=-k*a+yz(2)
sgu106这道题就转化成为了求k所能够取到的整数个数
首先,弄清出已知与未知。
我们已知xz,yz,也已知方程左边的x和y的取值范围为x1到x2,y1到y2,也已知a和b
我们只需要求出k即可。
对于方程(1),我们带入x1,x2当作x的值,那么可以求出k1,k2(k1<k2)
同理,带入(2),我们可以求出k3,k4.(k3<k4)
那么我们最后的答案ans=min(k2,k4)-max(k1,k3)+1即可。

Time complexity: O(N)

 

view code

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-01-08-10.51
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);

long long a , b , c;
long long x1 , x2 , y1 , y2;
long long x , y;

long long exgcd( long long a , long long b)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    else
    {
        long long t = exgcd(b , a %b ), s = x;
        x = y;
        y = s -( a /b) * y;
        return t;
    }
}

long long solve()
{
    scanf( "%lld %lld %lld" , & a , &b , & c);
    scanf( "%lld %lld %lld %lld" , & x1 , & x2 , & y1 , & y2);
    c = - c;

    if( a == 0 && b == 0 && c != 0)
    {
        return 0;
    }
    if( a == 0 && b == 0 && c == 0)
    {
        return ( x2 - x1 + 1) *( y2 - y1 + 1);
    }

    if( a == 0)
    {
        long long sign = 0;
        if( y1 <= c /b && y2 >= c /b && c %b == 0)
        {
            sign = 1;
        }
        return ( x2 - x1 + 1) * sign;
    }
    if(b == 0)
    {
        long long sign = 0;
        if( x1 <= c / a && x2 >= c / a && c % a == 0)
        {
            sign = 1;
        }
        return ( y2 - y1 + 1) * sign;
    }

    long long gcd = exgcd( a , b);
    long long ans = 0;

    if( c % gcd != 0)
    {
        return 0;
    }

    /* 求交集 */
    x = x *( c / gcd);
    y = y *( c / gcd);
    // 减小步长
    a /= gcd;
   b /= gcd;
    long long lx = ( x1 - x > 0 &&( x1 - x) %b != 0) ?
                  (( x1 - x) /b + 1) :
                  (( x1 - x) /b);
    long long rx = ( x2 - x < 0 &&( x2 - x) %b != 0) ?
                  (( x2 - x) /b - 1) :
                  (( x2 - x) /b);
    long long ly = ( y - y2 > 0 &&( y - y2) % a != 0) ?
                  (( y - y2) / a + 1) :
                  (( y - y2) / a);
    long long ry = ( y - y1 < 0 &&( y - y1) % a != 0) ?
                  (( y - y1) / a - 1) :
                  (( y - y1) / a);
    if( lx > rx)
    {
        swap( lx , rx);
    }
    if( ly > ry)
    {
        swap( ly , ry);
    }
    if( rx >= ly && ry >= lx)
    {
        ans = min( rx , ry) - max( lx , ly) + 1;
    }
    return ans;
}

int main( int argc , char ** argv)
{
    printf( "%lld" , solve());
    return 0;
}
目录
相关文章
|
5月前
数论——高斯消元
数论——高斯消元
34 0
|
11月前
|
C语言 C++
C++/C/PTA 找鞍点
一个矩阵元素的“鞍点”是指该位置上的元素值在该行上最大、在该列上最小。
87 0
[Codeforces] 1557 C Moamen and XOR(组合数学)
题意: 用 < 2k的数填充到长度为n的数组中,要使得数组中所有数& >= ^,问方案数 显然,当k == 1的时候,答案为1,只有当所有的数全为1的情况才可以满足题意 对于其他的情况{ 用小于2k的数进行填充,那么说明填充的数字的二进制位数最多可以有k kk位, 从数的个数的角度来说,奇数个1^ 之后的结果是1,偶数个1^ 之后的结果是0,而对于0来讲,不管多少个0,^起来结果都是0 只要有一个0,那么说这一位上&之后就是0,而为了让^为0,那么只能够选择偶数个1 如果某一位上&为1,那么^为1的情况需要讨论n的奇偶性
98 0
|
Java
HDOJ/HDU 1250 Hat's Fibonacci(大数~斐波拉契)
HDOJ/HDU 1250 Hat's Fibonacci(大数~斐波拉契)
82 0
|
Java
HDOJ/HDU 5686 Problem B(斐波拉契+大数~)
HDOJ/HDU 5686 Problem B(斐波拉契+大数~)
82 0
|
人工智能 BI 机器学习/深度学习
BZOJ 1041: [HAOI2008]圆上的整点【数论,解方程】
1041: [HAOI2008]圆上的整点 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4210  Solved: 1908[Submit][Status][Discuss] Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。
1240 0

热门文章

最新文章