由于 r 是最小值,所以一定会存在某个时刻走到圆的边界上,并且因为要回来,所以问题等价于将 D 划分成两个子序列,两个子序列分别可以走到边界。
考虑一个 D 数组能走到边界 r 的条件,如果 Di 中小于等于 r 的数的和 ≥r,则这些数一定能走到 r,大于 r 的进行调整即可。如果和小于 r,不妨设小于等于 r 的数走到了 p,下一步走 x,如果 x>p+r 就说明这时走 x 会走出圆,否则一定能刚好走到圆边界,于是最优条件一定是选大于 r 的最小的 x 走,如果这么走都会出去则走不到,否则走得到。
boolcheck(int l, int r){ int p = f._Find_next(l - 1); return p <= r; }
voiddickdreamer(){ std::cin >> n; for (int i = 1; i <= n; ++i) std::cin >> a[i]; std::sort(a + 1, a + 1 + n); int ss = 0; for (int i = 1; i < n; ++i) ss += a[i]; if (ss < a[n]) returnvoid(std::cout << "-1\n"); f[0] = 1; int sum = 0; a[n + 1] = 1e9; for (int r = a[n] / 2, p = 1; r <= a[n]; ++r) { for (; a[p] <= r; f |= (f << a[p++])) sum += a[p]; if (check(r, sum - r)) returnvoid(std::cout << r << '\n'); if (p <= n && check(r, sum + r - a[p])) returnvoid(std::cout << r << '\n'); if (p <= n - 1 && check(a[p] - r, sum + r - a[p + 1])) returnvoid(std::cout << r << '\n'); } }