260123A 供音树

给出两个长为 \(n\) 的数列 \(a_i,b_j\),对所有 \(1\le k\le n\) 计算

\[c_k=\max_{\gcd(i,j)=k}|a_i-b_j| \]

\[n\le 10^5 \]


省流:最值转判定转计数。

首先枚举绝对值内的符号做两遍,把绝对值拆掉。

考虑对于每个 \(k\) 保留原序列中所有 \(k\) 的倍数下标的位置,转化为对互质下标对最大化上式。

由于 \(\max\) 不具有可减性,因此不能直接上莫反。但是我们可以创造出一个可减性。

考虑二分答案。转化为对 \(a_i-b_j\ge w\) 的互质对 \((i,j)\) 计数。此时方案数就具有可减性。

我们在这里上莫反。我们希望一对 \((i,j)\) 在每一个 \(d|i,d|j\) 上贡献一次 \(\mu(d)\)

所以我们枚举 \(d\),将所有 \(d\) 的倍数下标的位置上的 \(a,b\) 分别排序,双指针维护贡献对数即可。

时间复杂度 \(\mathcal O(n\ln^2n\log V)\)


code
#include <algorithm>
#include <iostream>
#include <bitset>
 
const int N = 1e5 + 7;
#define rep(i,a,b) for(int i(a);i<=(b);++i)
typedef long long i64;
 
int mu[N];
std::bitset<N> ip;
std::basic_string<int> pr;
void prime() {
    mu[1] = 1;
    for(int i = 2; i < N; ++i) {
        if(!ip[i]) pr += i, mu[i] = -1;
        for(int& p: pr) {
            if(i * p >= N) break;
            ip[i * p] = 1;
            if(i % p == 0) break;
            mu[i * p] = -mu[i];
        }
    }
}
int n, a[N], b[N], wa[N], wb[N], m;
std::basic_string<int> ga[N], gb[N];
inline int solve() {
    for(int i = 1; i <= m; ++i)
        ga[i].clear(), gb[i].clear();
    for(int i = 1; i <= m; ++i) {
        if(!mu[i]) continue;
        for(int j = i; j <= m; j += i)
            ga[i] += wa[j], gb[i] += wb[j];
        std::sort(ga[i].begin(), ga[i].end());
        std::sort(gb[i].begin(), gb[i].end());
    }
    auto check = [](int w) {
        i64 res = 0;
        for(int i = 1; i <= m; ++i) {
            if(!mu[i]) continue;
            i64 T = 0;
            auto &gA = ga[i], &gB = gb[i];
            for(int i = 0, j = 0; i < (int)gA.size(); ++i) {
                while(j < (int)gB.size() && gB[j] <= gA[i] - w) ++j;
                T += j;
            }
            for(int i = 0, j = 0; i < (int)gB.size(); ++i) {
                while(j < (int)gA.size() && gA[j] <= gB[i] - w) ++j;
                T += j;
            }
            res += mu[i] * T;
        }
        return res;
    };
    int l = 0, r = 1e9 + 1;
    while(r - l > 1) {
        int m = (l + r) >> 1;
        if(check(m) > 0) l = m;
        else r = m;
    }
    return l;
}
 
int main() {
    std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
    prime(), std::cin >> n;
    rep(i, 1, n) std::cin >> a[i];
    rep(i, 1, n) std::cin >> b[i];
    rep(i, 1, n) {
        m = 0;
        for(int j = i; j <= n; j += i)
            ++m, wa[m] = a[j], wb[m] = b[j];
        std::cout << solve() << ' ';
    }
    std::cout << "\n";
}
posted @ 2026-01-23 23:16  CuteNess  阅读(14)  评论(0)    收藏  举报