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;
} 
京公网安备 11010502036488号