[ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解

发布时间 2023-08-21 17:22:48作者: MoyouSayuki

[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;
}