[ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解
[ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解
题目描述
求题目中式子的数量。
思路
因为 \(N\le 10^6\),所以考虑枚举 \(k\),那么变为求 \(ai+bj=x-ck, i, j\in[1,N]\),这个问题可以通过 Exgcd
算法求解。
首先考虑求出一组 \(i, j\) 的特解 \(x', y'\),根据通解 \(x = x' + tb, y = y' - ta\) 可以得知,\(x'+tb\in[1, N], y'-ta\in[1,N]\),解不等式之后得到下面的条件需要满足:
\[\lceil \dfrac{1-x'}{b} \rceil\le t\le\lfloor \dfrac{N-x'}{b} \rfloor\\
\lceil \dfrac{y'-N}{a}\rceil\le t\le \lfloor \dfrac{y'-1}{a} \rfloor
\]
因此 \(t\) 最小可以取到:
\[\max(\lceil \dfrac{1-x'}{b} \rceil, \lceil \dfrac{y'-N}{a}\rceil)
\]
\(t\) 最大可以取到:
\[\min(\lfloor \dfrac{N-x'}{b} \rfloor, \lfloor \dfrac{y'-1}{a} \rfloor)
\]
根据通解形式可以发现,\(t\) 的取值是连续的。
所以这个 \(k\) 对答案的贡献即为:
\[\max(\lceil \dfrac{1-x'}{b} \rceil, \lceil \dfrac{y'-N}{a}\rceil) -\min(\lfloor \dfrac{N-x'}{b} \rfloor, \lfloor \dfrac{y'-1}{a} \rfloor)
\]
注意如果是是负数就跳过,要手写 \(ceil(), floor()\),因为 c++ 默认向 \(0\) 取整。
时间复杂度:\(O(N+\log C)\)。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define int __int128
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
int n, a, b, c, X, ans;
int down(int a, int b) {
if(a >= 0) return a / b;
return -((-a + b - 1) / b);
}
int up(int a, int b) {
if(a >= 0) return (a + b - 1) / b;
return -((-a) / b);
}
int exgcd(int a, int b, int &x, int &y) {
if(!b) return x = 1, y = 0, a;
int d = exgcd(b, a % b, y, x);
return y -= a / b * x, d;
}
int x, y, d, aa, bb;
void work(int t) {
if(t <= 0) return ;
if(t % d) return ;
int xx = t / d * x, yy = t / d * y;
int l = max(up(1 - xx, bb), up(yy - n, aa));
int r = min(down(n - xx, bb), down(yy - 1, aa));
if(l > r) return ;
ans += r - l + 1;
}
inline int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch <= '9' && ch >= '0') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x;
}
void write(int x) {
if(x == 0) return ;
if(x > 0) write(x / 10);
putchar(x % 10 + '0');
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
n = read(), a = read(), b = read(), c = read(), X = read();
d = exgcd(a, b, x, y);
aa = a / d, bb = b / d;
for(int i = 1; i <= n; i ++) work(X - c * i);
if(ans == 0) cout << 0 << '\n';
else write(ans);
return 0;
}