题意:
给 定 整 数 : a , b , c , l 1 , r 1 , l 2 , r 2 , 对 方 程 a x + b y + c = 0 , 计 算 有 多 少 组 整 数 解 ( x 0 , y 0 ) , 给定整数:a,b,c,l_1,r_1,l_2,r_2,对方程ax+by+c=0,计算有多少组整数解(x_0,y_0), 给定整数:a,b,c,l1,r1,l2,r2,对方程ax+by+c=0,计算有多少组整数解(x0,y0),
满 足 : l 1 ≤ x 0 ≤ r 1 且 l 2 ≤ y 0 ≤ r 2 。 满足:l_1\le x_0\le r_1\ 且\ l_2\le y_0\le r_2。 满足:l1≤x0≤r1 且 l2≤y0≤r2。
输入:
整 数 a , b , c , l 1 , r 1 , l 2 , r 2 , 所 有 整 数 的 绝 对 值 均 不 超 过 1 0 8 。 整数a,b,c,l_1,r_1,l_2,r_2,所有整数的绝对值均不超过10^8。 整数a,b,c,l1,r1,l2,r2,所有整数的绝对值均不超过108。
输出:
一 个 整 数 表 示 答 案 。 一个整数表示答案。 一个整数表示答案。
Sample Input
1 1 -3
0 4
0 4
Sample Output
4
分析:
解 a x + b y + c = 0 , 用 扩 展 欧 几 里 得 算 法 , 记 d = g c d ( a , b ) , 解ax+by+c=0,用扩展欧几里得算法,记d=gcd(a,b), 解ax+by+c=0,用扩展欧几里得算法,记d=gcd(a,b),
先 解 方 程 a x + b y = d , 假 设 方 程 有 解 , 且 a > 0 , b > 0 , ( x 0 , y 0 ) 是 一 组 特 殊 解 , 先解方程ax+by=d,假设方程有解,且a>0,b>0,(x_0,y_0)是一组特殊解, 先解方程ax+by=d,假设方程有解,且a>0,b>0,(x0,y0)是一组特殊解,
则 方 程 通 解 的 形 式 为 : { x = x 0 + k b ′ y = y 0 − k a ′ , 其 中 b ′ = b d , a = a d . 则方程通解的形式为:\begin{cases}x=x_0+kb'\\y=y_0-ka'\end{cases},其中b'=\frac{b}{d},a=\frac{a}{d}. 则方程通解的形式为:{x=x0+kb′y=y0−ka′,其中b′=db,a=da.
然 后 我 们 将 x 和 y 同 时 扩 大 然后我们将x和y同时扩大 然后我们将x和y同时扩大 − c d \frac{-c}{d} d−c 倍 。 倍。 倍。
要 求 解 ( x , y ) 满 足 : { l 1 ≤ x ≤ r 1 l 2 ≤ y ≤ r 2 , 即 要求解(x,y)满足:\begin{cases}l_1\le x\le r_1\\l_2\le y\le r_2\end{cases},即 要求解(x,y)满足:{l1≤x≤r1l2≤y≤r2,即 { l 1 − x 0 b ′ ≤ k ≤ r 1 − x 0 b ′ y 0 − r 2 a ′ ≤ k ≤ y 0 − l 2 a ′ \begin{cases}\frac{l_1-x_0}{b'}\le k\le\frac{r_1-x_0}{b'}\\\\\frac{y_0-r_2}{a'}\le k\le \frac{y_0-l_2}{a'}\end{cases} ⎩⎪⎨⎪⎧b′l1−x0≤k≤b′r1−x0a′y0−r2≤k≤a′y0−l2
然 后 我 们 取 区 间 的 交 集 , 就 能 够 计 算 出 满 足 条 件 的 k 的 个 数 , 即 整 数 解 对 的 个 数 。 然后我们取区间的交集,就能够计算出满足条件的k的个数,即整数解对的个数。 然后我们取区间的交集,就能够计算出满足条件的k的个数,即整数解对的个数。
当 a < 0 时 , 我 们 可 以 计 算 ( − a ) x + b y = − c , 且 满 足 l 1 ≤ − x ≤ r 1 , l 2 ≤ y ≤ r 2 的 整 数 解 对 ( x , y ) 的 数 量 。 当a<0时,我们可以计算(-a)x+by=-c,且满足l_1\le -x\le r_1,l_2\le y\le r_2的整数解对(x,y)的数量。 当a<0时,我们可以计算(−a)x+by=−c,且满足l1≤−x≤r1,l2≤y≤r2的整数解对(x,y)的数量。
当 b < 0 时 , 同 理 。 当b<0时,同理。 当b<0时,同理。
当 − c < 0 时 , 在 方 程 两 边 同 时 乘 − 1 , 即 将 a 变 为 − a , b 变 为 − b , 就 能 够 不 更 改 解 所 在 的 区 间 。 当-c<0时,在方程两边同时乘-1,即将a变为-a,b变为-b,就能够不更改解所在的区间。 当−c<0时,在方程两边同时乘−1,即将a变为−a,b变为−b,就能够不更改解所在的区间。
这 样 我 们 能 够 减 少 分 类 讨 论 的 情 况 。 这样我们能够减少分类讨论的情况。 这样我们能够减少分类讨论的情况。
特殊情况:
① 、 a = b = 0 , ①、a=b=0, ①、a=b=0,
Ⅰ 、 c = 0 , 此 时 任 意 的 ( x , y ) 均 满 足 条 件 , 答 案 : ( r 1 − l 1 + 1 ) × ( r 2 − l 2 + 1 ) \qquadⅠ、c=0,此时任意的(x,y)均满足条件,答案:(r_1-l_1+1)×(r_2-l_2+1) Ⅰ、c=0,此时任意的(x,y)均满足条件,答案:(r1−l1+1)×(r2−l2+1)
Ⅱ 、 c ≠ 0 , 无 解 。 \qquad Ⅱ、c≠0,无解。 Ⅱ、c=0,无解。
② 、 a = 0 , b ≠ 0 , 解 b y = − c , 先 判 断 b 是 否 能 够 整 除 ( − c ) , 若 不 能 , 答 案 为 0 ; 再 判 断 − c b 是 否 在 区 间 [ l 2 , r 2 ] 内 , 若 在 , 答 案 为 r 1 − l 1 + 1 ; 否 则 为 0. ②、a=0,b≠0,解by=-c,先判断b是否能够整除(-c),若不能,答案为0;\\\qquad再判断-\frac{c}{b}是否在区间[l_2,r_2]内,若在,答案为r_1-l_1+1;否则为0. ②、a=0,b=0,解by=−c,先判断b是否能够整除(−c),若不能,答案为0;再判断−bc是否在区间[l2,r2]内,若在,答案为r1−l1+1;否则为0.
③ 、 a ≠ 0 , b = 0 , 同 理 。 ③、a≠0,b=0,同理。 ③、a=0,b=0,同理。
注意:
区 间 左 端 点 处 应 当 为 上 取 整 , 右 端 点 应 当 为 下 取 整 。 区间左端点处应当为上取整,右端点应当为下取整。 区间左端点处应当为上取整,右端点应当为下取整。
x 和 y 的 范 围 在 1 0 8 , 在 扩 展 欧 几 里 得 计 算 的 过 程 中 可 能 会 爆 i n t , 故 x , y 要 开 l l , 尤 其 要 注 意 有 乘 法 的 部 分 。 x和y的范围在10^8,在扩展欧几里得计算的过程中可能会爆int,故x,y要开ll,尤其要注意有乘法的部分。 x和y的范围在108,在扩展欧几里得计算的过程中可能会爆int,故x,y要开ll,尤其要注意有乘法的部分。
由 于 区 间 端 点 可 能 有 负 数 , 故 向 上 取 整 和 和 向 下 取 整 时 最 好 用 c e i l 和 f l o o r 函 数 来 完 成 。 由于区间端点可能有负数,故向上取整和和向下取整时最好用ceil和floor函数来完成。 由于区间端点可能有负数,故向上取整和和向下取整时最好用ceil和floor函数来完成。
因 为 负 数 除 整 数 , 默 认 是 向 上 取 整 。 因为负数除整数,默认是向上取整。 因为负数除整数,默认是向上取整。
代码:
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int exgcd(int a,int b,ll &x,ll &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int main()
{
int a,b,c,l1,r1,l2,r2;
ll x,y;
ll ans;
cin>>a>>b>>c>>l1>>r1>>l2>>r2;
if(a==0&&b==0)
{
if(c!=0) ans=0;
else ans=(ll)(r1-l1+1)*(r2-l2+1);
}
else if(a==0&&b!=0)
{
if(abs(c)%b!=0) ans=0;
else
{
int t=-c/b;
if(t>=l2&&t<=r2) ans=r1-l1+1;
else ans=0;
}
}
else if(a!=0&&b==0)
{
if(abs(c)%a!=0) ans=0;
else
{
int t=-c/a;
if(t>=l1&&t<=r1) ans=r2-l2+1;
else ans=0;
}
}
else
{
if(c>0) c=-c, a=-a, b=-b;
if(a<0) a=-a, l1=-l1, r1=-r1, swap(l1,r1);
if(b<0) b=-b, l2=-l2, r2=-r2, swap(l2,r2);
int d=exgcd(a,b,x,y);
if(abs(c)%d!=0) ans=0;
else
{
int b1=b/d, a1=a/d;
x=x/d*(-c), y=y/d*(-c);
int L1=ceil((double)(l1-x)/b1), R1=floor((double)(r1-x)/b1);
int L2=ceil((double)(y-r2)/a1), R2=floor((double)(y-l2)/a1);
int L=max(L1,L2), R=min(R1,R2);
ans=max(0,R-L+1);
}
}
cout<<ans<<endl;
return 0;
}