正解应该是推出式子,用 O ( 1 ) O(1) O(1) 的方法求解。
但是由于实在没太看懂,然后在牛客上翻到一个 O ( n ) O(\sqrt{n}) O(n) 的做法,理解之后附在下面。
- 喝咖啡的时候体力值 u u u 必然满足 u ⩽ C ( C + 1 ) 2 u \leqslant \frac{C(C + 1)}{2} u⩽2C(C+1)
假设在体力值为 u u u 的时候开始喝(一次),那么之后的体力值为: [ u , u , ⋯ , u ⏟ C , u − c − 1 , u − c − 2 , ⋯ , 1 ] [\underbrace{u, u, \cdots, u}_{C}, u - c - 1, u - c - 2, \cdots, 1] [C u,u,⋯,u,u−c−1,u−c−2,⋯,1]
对比不喝咖啡,体力值为: [ u , u − 1 , u − 2 , ⋯ , 2 , 1 ] [u, u - 1, u - 2, \cdots, 2, 1] [u,u−1,u−2,⋯,2,1]
两者做差,为 C − C ( C − 1 ) 2 − u C - \frac{C(C - 1)}{2} - u C−2C(C−1)−u 。为了让该式子非负,则 u ⩽ C ( C + 1 ) 2 u \leqslant \frac{C(C + 1)}{2} u⩽2C(C+1)。
- 如果从某个时刻开始喝咖啡,则此后喝咖啡是必然不间断的。
如果在第一 次喝咖啡后存在某个时刻体力值为 i i i ,可以喝咖啡却没有喝,则必然可以将体力值为 i i i 之前的第一 次喝咖啡时刻推迟到 i i i 而其他喝咖啡时刻不变,这样调整后总完成度一定会变好。(by官方题解)
- 应该从 C C C 的整数倍开始喝
假设在体力值为 u u u 的时候开始喝,那么之后的体力值为: [ u , u , ⋯ , u ⏟ C , u − c − 1 , u − c − 1 , . . . ] [\underbrace{u, u, \cdots, u}_{C}, u - c - 1, u - c - 1, ...] [C u,u,⋯,u,u−c−1,u−c−1,...]
假设在体力值为 u − 1 u-1 u−1 的时候开始喝,那么之后的体力值为: [ u , u − 1 , u − 1 , ⋯ , u − 1 ⏟ C , u − c − 2 , u − c − 2 , . . . ] [u, \underbrace{u - 1, u - 1, \cdots, u - 1}_{C}, u - c - 2, u - c - 2, ...] [u,C u−1,u−1,⋯,u−1,u−c−2,u−c−2,...]
两者做差,差为 C ∗ k − u C*k - u C∗k−u, 则说明当 u u u 为 C C C 的倍数时开始喝最佳。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll t, s, c;
ll k, res, tmp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> t;
while(t --)
{
cin >> s >> c;
// 直接喝咖啡
k = s / (c + 1) + 1;
res = k * c * (s + s % (c + 1)) / 2;
// s~(j+1) 先不喝,从j开始喝
for (ll j = c; j <= min(s, c * (c + 1) / 2); j += c)
{
k = j / (c + 1) + 1;
tmp = (s + j + 1) * (s - j) / 2 + k * c * (j + j % (c + 1)) / 2;
res = max(res, tmp);
}
cout << res << '\n';
}
}