Codeforces gym 101611A. Walk of Three Advertising Strategy 题解
题解
我们可以把递推式子简化为: \[
\begin{aligned}
b_{i+1}=b_i+\min{\{b_i,\frac{n-b_i}{2}\}+x_i}\\
\sum_{i=1}^{n}x_i\leq k
\end{aligned}
\]
我们想象这个过程,可以分为两步:先是一个类似二倍的增加,在接近 \(n\) 时变为由剩余部分进行限制,每次类似把剩下的一半填满。
由于要求天数尽量少,则第一部分可以把 \(x_i\) 尽可能往第一天放,可以保证对 \(\times 2\) 的贡献最多,之后我们到第二部分,这里我们发现,如果在距离 \(n\) 还比较远的时候放 \(x_i\),效益不如把剩下的 \(x_i\) 放在最后,用来“兜底最后一天的观看人数”,“兜底”的越多,越容易尽快停止,而从 \(16\) 减半下去和从 \(15\) 减半下去影响的数量级对于 \(\log\) 这样级别的下降效益比较低,上面的两个贪心结合枚举第一天和最后一天的分配人数就可以枚举得到最小的天数。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <cstdio> #include <cctype> #include <algorithm> #include <cstring> #include <iostream> #include <cassert> #include <cmath> using namespace std; typedef long long ll; template <typename _Tp> void read(_Tp &a, char c = 0, int f = 1) { for(c = getchar(); !isdigit(c); c = getchar()) if(c == '-') f = -1; for(a = 0; isdigit(c); a = a * 10 + c - '0', c = getchar()); a *= f; } template <typename _Tp> void write(_Tp a) { if(a < 0) putchar('-'), a = -a; if(a > 9) write(a / 10); putchar(a % 10 + '0'); }
ll n, k;
int main() { read(n), read(k); ll ans = 1e18; for(int s = 1; s <= k - 1; s++) { ll c = s; ll r = k - s; ll _ans = 0; while(1) { if(n - c <= r) { _ans++; break; } c = c + min(c, (n - c) / 2); _ans++; } ans = min(ans, _ans); } write(ans), putchar('\n'); return 0; }
|