Codeforces Round #785 (Div. 2) - D. Lost Arithmetic Progression
GCD
题意
有 2 个等差数列 A,B,它们公有的项组成新的等差数列 C;
现在给出 B 的(首项,公差,项数)= (b,q,y),C 的(首项,公差,项数)= (c,r,z)
求满足条件的 A 的数量,如果有无穷多个输出 -1
思路
记 A,B,C 的首项,公差,末项分别为 \(l[0/1/2],d[0/1/2],r[0/1/2]\)
-
首先要明确 \(lcm(d[0],d[1])=d[2]\)
-
先排除 B,C 就不满足条件的情况
-
B 一定要完全覆盖 C,因此当 \(l[1]>l[2]\;or\;r[1]<r[2]\;or\;d[1]\nmid d[2]\) 时,不满足 C 是 B 的某些项,此时 A 无论是什么都没用,输出 0
-
B 与 C 在 模 \(d[1]\) 意义 下要是对齐的,因此
ll x = (l[1] % d[1] + d[1]) % d[1]; ll y = (l[2] % d[1] + d[1]) % d[1]; if (x != y) return 0;
-
-
至此 B,C 已经协调了,再找 A 的数量 (画个图会很好理解)
- 如果两端中至少有一端,B 比 C 延长的长度小于 \(d[2]\), 则 A 在这一段即使无限长也可以,输出 -1
- 反之,如果两端 B 比 C 延长的长度都 >= \(d[2]\) 则 A 在任何一端最多延长 \(d[2]-1\), 此时枚举 \(d[2]\) 的因子 \(g\),如果满足\(lcm(g,d[1])=d[2]\), 则当前的 \(g\) 可以作为 \(d[0]\), 那 A 在任何一端有 \(0,1,...\frac {d[2]-1}g\) 种可能,因为 \(g\mid d[2]\), 所以当前的 \(g\) 对答案的贡献就是 \((\frac {d[2]}g)^2\)
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
#define endl "\n"
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
ll l[3], r[3], d[3], c[3];
void add(ll &a, ll b)
{
a += b;
if (a >= mod)
a -= mod;
}
ll gcd(ll a, ll b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
ll lcm(ll a, ll b)
{
return a / gcd(a, b) * b;
}
ll calc(ll g)
{
return (d[2] / g) * (d[2] / g) % mod;
}
ll solve()
{
r[1] = l[1] + d[1] * (c[1] - 1);
r[2] = l[2] + d[2] * (c[2] - 1);
if (l[1] > l[2] || r[1] < r[2] || d[2] % d[1] != 0)
return 0;
ll x = (l[1] % d[1] + d[1]) % d[1];
ll y = (l[2] % d[1] + d[1]) % d[1];
if (x != y)
return 0;
if (l[2] - l[1] < d[2] || r[1] - r[2] < d[2])
return -1;
ll ans = 0;
for (int i = 1; i <= d[2] / i; i++)
{
if (d[2] % i)
continue;
ll p = i, q = d[2] / p;
if (lcm(p, d[1]) == d[2])
add(ans, calc(p));
if (p != q && lcm(q, d[1]) == d[2])
add(ans, calc(q));
}
return ans;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> l[1] >> d[1] >> c[1];
cin >> l[2] >> d[2] >> c[2];
cout << solve() << endl;
}
return 0;
}