CF710D Two Arithmetic Progressions
原题链接
即求在\([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\times 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\)即可
写成公式就是\(\left\lfloor\dfrac{R - (a_1x_0 + b_1)}{a_1MOD}\right\rfloor - \left\lceil\dfrac{L - (a_1x_0 + b_1)}{a_1MOD}\right\rceil + 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;
}
posted on 2021-01-14 20:22 Iowa_Battleship 阅读(111) 评论(2) 编辑 收藏 举报