G. Greater Integer, Better LCM

前言

题解有点看不懂,自己想了个比较直接的做法。

Solution

考虑的因数是由哪些组成的,于是发现这两个数选到最终要包含所有,所以直接考虑枚举其中一个数,那么另一个数能取的范围就是“至少包含当前数的补集的所有数”,换句话说,我们选定一个数后,这个数有哪些选满了已知,那么另一个数一定要把没选满的都选满,所以只要能预处理出“至少某几位选满时的最小值”就可以了。

这个预处理其实很简单,先直接dfs求出恰好某几位选满时的答案,然后直接SOSDP即可。

最终统计答案时的dfs和预处的dfs几乎完全一致。

中间特别注意一下选出来的数要或者

至于复杂度,dfs的复杂度不会超过,而SOSDP的过程是,可以轻松通过。

ll num[N];
ll a, b, ans;
ll p[N], q[N], MAXN;
int n;
void dfs(int step, ll x, int S, int opt) {
    if (step > n) {
        if (opt) {
            if (x >= a)num[S] = min(num[S], x - a);
        }
        else {
            if (x < b)return;
            if (num[S ^ ((1 << n) - 1)] != MAXN)
                ans = min(ans, x - b + num[S ^ ((1 << n) - 1)]);
        }
        return;
    }
    ll now = 1;
    for (int i = 0; i <= q[step]; ++i, now *= p[step])
        dfs(step + 1, x * now, i == q[step] ? (S | (1 << step - 1)) : S, opt);
}

int main() {
    n = fast_IO::read();
    for (int i = 1; i <= n; ++i)
        p[i] = fast_IO::read(), q[i] = fast_IO::read();
    a = fast_IO::read(), b = fast_IO::read();
    MAXN = 1e30;
    for (int i = 0; i < (1 << n); ++i)num[i] = MAXN;
    dfs(1, 1, 0, 1);
    for (int i = (1 << n) - 1; ~i; --i) {
        for (int j = 0; j < n; ++j) {
            if (!((i >> j) & 1))continue;
            num[i ^ (1 << j)] = min(num[i ^ (1 << j)], num[i]);
        }
    }
    ans = MAXN;
    dfs(1, 1, 0, 0);
    fast_IO::write(ans);
    return 0;
}