Editorial for Bedao Grand Contest 11 - K-ONLY


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Gọi ~f(x, y, k)~ là tổng các tích ~i \times j~ của các cặp ~i, j~ thỏa ~i \leq x, j \leq y~ và ~gcd(i, j) = k~.

Vậy đáp án cho bài toán là ~f(b, d, k) - f(a - 1, d, k) - f(b, c - 1, k) + f(a - 1, c - 1, k)~

Ta có ~f(x, y, k) = f(x / k, y / k, 1) \times k^2~, bài toán chuyển về tính ~f(x, y, 1)~.

Công thức tính ~f(x, y, 1)~ như sau:

~f(x, y, 1) = \displaystyle\sum_{k = 1}^{min(x, y)}{ g(x / k, y / k) \times mo[k] \times k^2 } ~, trong đó, ~mo~ là hàm mobius, ~g(a, b)~ là tổng các tích ~i \times j~ của các cặp ~i, j~ mà ~i \leq a, j \leq b~, ta có ~g(a, b) = (a \times (a + 1) / 2) \times (b \times (b + 1) / 2)~.

Nhận xét rằng, có thể chia đoạn ~[1;min(x, y)]~ thành khoảng ~\sqrt{min(x, y)}~ đoạn ~[l; r]~ mà ~x / k~ không đổi và ~y / k~ không đổi với mọi ~k~ thuộc đoạn ~[l;r]~.

Với mỗi đoạn ~[l;r]~ như vậy, ta có ~\displaystyle\sum_{k = l}^{r}{ g(x / k, y / k) \times mo[k] \times k^2 = g(x / l, y / l) \times \displaystyle\sum_{k = l}^{r}{mo[k] \times k^2} } ~, phần ~(\displaystyle\sum_{k = l}^{r}{mo[k] \times k^2})~ có thể được tính trong ~O(1)~ bằng cách tạo trước mảng tổng tiền tố của hàm ~mo[k] \times k^2 ~.

Vậy mỗi đoạn ~[l; r]~ chỉ cần ~O(1)~ để tính toán, độ phức tạp cho mỗi bộ dữ liệu là ~O(\sqrt{min(b/k, d/k)})~ hay ~O(\sqrt{min(b, d)})~, tổng độ phức tạp là ~O(q\sqrt{b})~.

Code mẫu

#include <bits/stdc++.h>

#define fi first
#define se second
#define For(i, a, b) for (int i=a;i<=b;++i)
#define Ford(i, a, b) for(int i=a;i>=b;--i)

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<ii> vii;

const int N = 2 * 1e5 + 5;
const ll mod = 1e9 + 7;

ll p[N], mu[N], m2[N];

int mobius(int x) {
    int c = 0;
    while (x > 1) {
        if (x / p[x] % p[x] == 0) return 0;
        c++;
        x /= p[x];
    }
    return (c & 1 ? -1 : 1);
}
void prepare(int n) {
    For(i, 1, n) p[i] = i;
    for (int i = 2; i * i <= n; ++i) {
        if (p[i] == i) {
            for (ll j = i * i; j <= n; j += i) {
                p[j] = i;
            }
        }
    }

    For(i, 1, n) m2[i] = (m2[i - 1] + 1LL * i * i %mod * (mobius(i) + mod)) % mod;
}

ll calc(ll x, ll y) {
    return x * (x + 1) / 2 % mod * (y * (y + 1) / 2 % mod) % mod;
}
ll f(int x, int y) {
    if (x > y) swap(x, y);
    ll ans = 0;

    int l = 1;
    while (l <= x) {
        int r = min(x / (x / l) + 1, y / (y / l) + 1);

        (ans += calc(x / l, y / l) * (m2[r - 1] - m2[l - 1] + mod)) %= mod;
        l = r;
    }
    return ans;
}

void solve() {
    int a, b, c, d, g;
    cin >> a >> b >> c >> d >> g;
    if (g < 1) cout << "0\n";
    else
        cout << (f(b / g, d / g) - f((a - 1) / g, d / g) - f(b / g, (c - 1) / g) + f((a - 1) / g, (c - 1) / g) + mod + mod) * g % mod * g % mod << "\n";
}

int main() {
//  freopen(".inp","r",stdin);
//  freopen(".out","w",stdout);

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);

    prepare(100000);

    int t; cin >> t;
    while (t--) solve();

    return 0;
}

Comments

Please read the guidelines before commenting.


There are no comments at the moment.