原题链接
即求在([L,R])之间有多少个整数(K)满足(K = a_1x + b_1 = a_2y + b_2),其中(x,y)为自然数
很容易想到将等式移项,变为(a_1x + a_2(-y) = b_2 - b_1)
那么很明显可以用扩欧来求出一组(x,y)的特解,并将特解移至自然数范围内的最小解
因为原式是等式,接下来我们只需要关注其中一个解,例如(x)
设扩欧求出的(x)的通解为(x_0 + k imes MOD),其中(MOD = a_2/gcd),因为特解(x_0)是摸(MOD)下最小自然数解,所以(k)也为自然数
题目要求的是([L,R])之间有多少个整数(K)满足(K = a_1x + b_1)
将通解代入,即求([L,R])之间有多少个整数(K)满足(K = (a_1MOD)k + a_1x_0 + b_1)
那么最后就是求有多少(k)能让整数落于([L,R]),因为(k)连续,所以直接算不大于(R)的最大(k)和不小于(L)的最小(k)即可
写成公式就是(leftlfloordfrac{R - (a_1x_0 + b_1)}{a_1MOD}
ight
floor - leftlceildfrac{L - (a_1x_0 + b_1)}{a_1MOD}
ight
ceil + 1)
但要注意可能会除出来负数,因为(k)为自然数,要手动调到(0),具体见代码。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int mod = 1073741824;
inline ll re()
{
ll x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
ll exgcd(ll a, ll b, ll& x, ll& y)
{
if (!b)
{
x = 1; y = 0;
return a;
}
ll gcd = exgcd(b, a % b, y, x);
y -= a / b * x;
return gcd;
}
int main()
{
ll i, j, k, n, m, a_1, a_2, b_1, b_2;
a_1 = re(); b_1 = re(); a_2 = re();
b_2 = re(); n = re(); m = re();
ll x, y, gcd = exgcd(a_1, a_2, x, y);
if ((b_2 - b_1) % gcd)//无解
return printf("0"), 0;
x *= (b_2 - b_1) / gcd;//一组特解
y *= (b_2 - b_1) / gcd;
ll MOD = a_2 / gcd;
x = (x % MOD + MOD) % MOD;//先让x落于自然数范围
y = -((b_2 - b_1) - a_1 * x) / a_2;//算出此时的y
if (y < 0)//若y还是负数就让y落于自然数范围并计算出x,此时x一定为自然数
{
ll MODY = a_1 / gcd;
y = (y % MODY + MODY) % MODY;
x = ((b_2 - b_1) + a_2 * y) / a_1;
}
m = floor(1.0 * (m - a_1 * x - b_1) / (a_1 * MOD));//计算最大的k
if (m < 0)//不大于右边界的最大k都为负,那么一定不存在解
return printf("0"), 0;
n = ceil(1.0 * (n - a_1 * x - b_1) / (a_1 * MOD));//计算最小的k
if (n < 0) n = 0;//k不能小于0
printf("%lld", m - n + 1);
return 0;
}